diff --git a/sdk/ai/azure-ai-agents/azure/ai/agents/_utils/model_base.py b/sdk/ai/azure-ai-agents/azure/ai/agents/_utils/model_base.py index 512d10f7c64a..7ec44978519b 100644 --- a/sdk/ai/azure-ai-agents/azure/ai/agents/_utils/model_base.py +++ b/sdk/ai/azure-ai-agents/azure/ai/agents/_utils/model_base.py @@ -816,16 +816,16 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur # is it optional? try: - if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore + if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore # pylint: disable=unidiomatic-typecheck if len(annotation.__args__) <= 2: # pyright: ignore if_obj_deserializer = _get_deserialize_callable_from_annotation( - next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore + next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore # pylint: disable=unidiomatic-typecheck ) return functools.partial(_deserialize_with_optional, if_obj_deserializer) # the type is Optional[Union[...]], we need to remove the None type from the Union annotation_copy = copy.copy(annotation) - annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore + annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore # pylint: disable=unidiomatic-typecheck return _get_deserialize_callable_from_annotation(annotation_copy, module, rf) except AttributeError: pass diff --git a/sdk/ai/azure-ai-agents/azure/ai/agents/models/_patch.py b/sdk/ai/azure-ai-agents/azure/ai/agents/models/_patch.py index 70a0891dc74b..d7e7d5aa8586 100644 --- a/sdk/ai/azure-ai-agents/azure/ai/agents/models/_patch.py +++ b/sdk/ai/azure-ai-agents/azure/ai/agents/models/_patch.py @@ -333,9 +333,9 @@ def _map_type(annotation) -> Dict[str, Any]: # pylint: disable=too-many-return- if origin is Union: args = get_args(annotation) # If Union contains None, it is an optional parameter - if type(None) in args: + if type(None) in args: # pylint: disable=unidiomatic-typecheck # If Union contains only one non-None type, it is a nullable parameter - non_none_args = [arg for arg in args if arg is not type(None)] + non_none_args = [arg for arg in args if arg is not type(None)] # pylint: disable=unidiomatic-typecheck if len(non_none_args) == 1: schema = _map_type(non_none_args[0]) if "type" in schema: diff --git a/sdk/ai/azure-ai-projects/.env.template b/sdk/ai/azure-ai-projects/.env.template index 0ca16cf1517e..76c795cfaf62 100644 --- a/sdk/ai/azure-ai-projects/.env.template +++ b/sdk/ai/azure-ai-projects/.env.template @@ -57,6 +57,9 @@ A2A_USER_INPUT= AZURE_TEST_RUN_LIVE=false AZURE_SKIP_LIVE_RECORDING=true +#Used by hosted agent +FOUNDRY_HOSTED_AGENT_NAME= + # Used in Fine-tuning tests COMPLETED_OAI_MODEL_SFT_FINE_TUNING_JOB_ID= COMPLETED_OAI_MODEL_RFT_FINE_TUNING_JOB_ID= @@ -88,6 +91,6 @@ RUN_EXTENDED_FINE_TUNING_LIVE_TESTS=false # - SAMPLE_TEST_ERROR_LOG: Sample crashed with an exception during execution # - SAMPLE_TEST_FAILED_LOG: Sample ran successfully but LLM validation failed (incorrect output) # - SAMPLE_TEST_PASSED_LOG: Sample ran successfully and LLM validation passed (correct output) -# SAMPLE_TEST_PASSED_LOG=_success_.log -# SAMPLE_TEST_FAILED_LOG=_failed_.log -# SAMPLE_TEST_ERROR_LOG=_errors_.log +SAMPLE_TEST_PASSED_LOG=_success_.log +SAMPLE_TEST_FAILED_LOG=_failed_.log +SAMPLE_TEST_ERROR_LOG=_errors_.log diff --git a/sdk/ai/azure-ai-projects/.github/skills/README.md b/sdk/ai/azure-ai-projects/.github/skills/README.md new file mode 100644 index 000000000000..7ea120484d10 --- /dev/null +++ b/sdk/ai/azure-ai-projects/.github/skills/README.md @@ -0,0 +1,33 @@ +# CoPilot skills for azure-ai-projects development + +## Prerequisite + +* Clone the `azure-sdk-for-python` repo to your local machine, if you don't already have it: + ``` + git clone https://github.com/Azure/azure-sdk-for-python.git + ``` +* Change to the directory `sdk\ai\azure-ai-projects`. +* Switch to the current feature branch: `git switch feature/azure-ai-projects/2.2.0`. +* Make sure you don't have any files edited or added in this branch (clean `git status` state). + +## Emit from TypeSpec and create a PR + +### Using GitHub CoPilot in VSCode + +* Open VSCode in the current folder. +* Open the CoPilot chat window ("Toggle Chat"). +* Make sure you are in "Agent" mode. +* Start typing `/azure-ai-projects` and press tab to auto complete it to `/azure-ai-projects-emit-from-typespec`, then press Enter. +* Answer some questions and approve execution to go through the workflow + +### Using CoPilot CLI or Agency Copilot CLI + +* Install [GitHub CoPilot CLI](https://docs.github.com/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli) or [Agency CoPilot CLI](https://aka.ms/agency) (VPN required) if you don't already have it. +* Run CoPilot CLI by typing `copilot` +* Start typing `/azure-ai-projects` and press tab to auto complete it to `/azure-ai-projects-emit-from-typespec`, then press Enter. +* Answer some questions and approve execution to go through the workflow + + + + + diff --git a/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-emit-from-typespec/SKILL.md b/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-emit-from-typespec/SKILL.md new file mode 100644 index 000000000000..190df28bcbd0 --- /dev/null +++ b/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-emit-from-typespec/SKILL.md @@ -0,0 +1,234 @@ +--- +name: azure-ai-projects-emit-from-typespec +license: MIT +metadata: + version: "1.0.0" + distribution: local +description: "Emit the azure-ai-projects Python SDK from TypeSpec, apply post-emitter fixes, update changelog, and create a Pull Request. WHEN: \"emit SDK from TypeSpec\", \"generate azure-ai-projects SDK\", \"update azure-ai-projects from TypeSpec\", \"emit from TypeSpec\", \"regenerate azure-ai-projects\". DO NOT USE FOR: other Azure SDK packages, manual code edits without TypeSpec. INVOKES: azsdk-common-generate-sdk-locally skill, post-emitter-fixes.cmd script, git commands, gh CLI for PR creation." +compatibility: + requires: "azure-sdk-mcp server, local azure-sdk-for-python clone, git, gh CLI" +--- + +# Emit azure-ai-projects Python SDK from TypeSpec + +This skill guides Copilot through emitting the azure-ai-projects Python SDK from TypeSpec, +applying post-emitter fixes, updating the changelog, installing package from sources and creating a Pull Request. + +**Working directory:** `sdk/ai/azure-ai-projects` + +**Skills:** This workflow relies on skills defined under `.github/skills/` at the root of the repository. Use those skills for SDK generation, building, changelog updates, and other SDK lifecycle operations instead of running commands directly. In particular: + +- **`azsdk-common-generate-sdk-locally`** – For generating SDK from TypeSpec, building, running checks/tests, updating changelog, metadata, and version. + +--- + +## Step 1: Gather information from the user + +Ask the user the following questions **one at a time**, waiting for each answer before proceeding. + +### 1a. Topic branch name + +Ask the user to choose **one** of the following two options for the target topic branch: + +1. **Create a new topic branch (with default branch name)** – Create a new topic branch for the emitted changes. If selected, this default branch name will be used "/", where `github-userid` is the user's GitHub ID and `DD-MM-HHMM` is the current date-time using date, month, hour and minute. For example, if the GitHub ID is "dargilco" and the current date and time is May 1st, 2026 at 8:13am, the default branch name would be `dargilco/emit-from-typespec-01-05-0813`. This should be the default option, and the default branch name should be displayed. If you press enter without typing anything, this option will be selected. + +2. **Create a new topic branch (branch name given by user)** - Ask the user for the branch name. Mention that a common format is "/". If the user enters a branch name `feature/azure-ai-projects/2.2.0` then stop and report that they cannot emit directly to the current feature branch. + +3. **Emit to current branch** – Emit directly to the current branch without creating a new topic branch. This is not common, but may be necessary if the user is re-running this workflow because of a previous failure, where the topic branch was already created. If the current branch is named `feature/azure-ai-projects/2.2.0` then stop and report that they cannot emit directly to the current feature branch. + +### 1b. TypeSpec source + +Ask the user to choose **one** of the following three options for the TypeSpec source: + +1. **Latest commit on `feature/foundry-release`** – Automatically find the latest commit to the `feature/foundry-release` branch in [Azure/azure-rest-api-specs](https://github.com/Azure/azure-rest-api-specs) that touched files under `specification/ai-foundry/data-plane/Foundry`, and use that commit hash. This should be the default option. If you press enter without typing anything, this option will be selected. + +2. **Local TypeSpec folder** – Emit from a local clone of the [azure-rest-api-specs](https://github.com/Azure/azure-rest-api-specs) repository. If selected, ask for the **full folder path** to the TypeSpec project. This is the folder ending with `\specification\ai-foundry\data-plane\Foundry`. If it does not end with that string, stop and report the error to the user. Do not continue. + +3. **TypeSpec commit hash** – Emit from a specific commit in the [azure-rest-api-specs](https://github.com/Azure/azure-rest-api-specs) repository. If selected, ask for the **full commit SHA** (40 characters). + + +--- + +## Step 2: Record the current branch + +Before creating the topic branch, record the name of the **current Git branch**. This is the branch that the topic branch will be created from, and the branch the PR will target. + +``` +git branch --show-current +``` + +Save this as `BASE_BRANCH`. + +--- + +## Step 3: Create the topic branch + +Create the topic branch off the current branch and switch to it: + +``` +git fetch +git switch -c origin/ +``` + +Replace `` with the name provided by the user in Step 1a. + +--- + +## Step 4: Emit SDK from TypeSpec + +Use the **`azsdk-common-generate-sdk-locally`** skill to generate the SDK code. The skill knows how to invoke `azsdk_package_generate_code` and related MCP tools. + +Provide the skill with the TypeSpec source selected by the user. With is either: + +- **Local folder:** Pass the local spec repo path for local generation. Or, +- **Commit hash:** Update `commit:` in `tsp-location.yaml` to the full SHA first, then invoke the skill for generation. + +Note: +- You are only allowed to use the `tsp-client update` command. Do not use any of the other `tsp-client` commands. +- If you are generating from local TypeSpec folder, do not edit the file `tsp-location.yaml`. Leave it as is. It should not be used by the emitter. +- If you are generating from local TypeSpec folder, make sure that the local folder path you provide `tsp-client update --local-spec-repo` ends with `specification\ai-foundry\data-plane\Foundry`. +- **If the generation fails**, stop and report the error to the user. Do not continue. + +--- + +## Step 5: Revert changes to file pyproject.toml + +After the emit, there will be changes to `pyproject.toml` that are not needed. Revert any changes to `pyproject.toml` by running: + +``` +git restore pyproject.toml +``` + +--- + +## Step 6: Commit and push + +Stage all changes (excluding file names that start with `.env`), commit, and push the topic branch: + +``` +git add -A -- ':!.env*' +git commit -m "Part 1: Emit SDK from TypeSpec" + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>" +git push -u origin +``` + +--- + +## Step 7: Run post-emitter fixes + +After a successful emit, run the post-emitter fix script located in the `sdk/ai/azure-ai-projects` folder: + +``` +post-emitter-fixes.cmd +``` + +This script applies azure-ai-projects-specific corrections to the emitted code (restores `pyproject.toml`, fixes enum names, patches Sphinx doc-string issues, and runs `black` formatting). + +**If the script fails**, stop and report the error to the user. Do not continue. Do not attempt to analyze the script failures and fix them with Copilot. The script should be fixed by the engineering team if it is not working. + +--- + +## Step 8: Commit and push + +Stage all changes (excluding file names that start with `.env`), commit, and push the topic branch: + +``` +git add -A -- ':!.env*' +git commit -m "Part 2: Apply post-emitter-fixes.cmd" + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>" +git push -u origin +``` + +--- + +## Step 9: Fix patched code related to preview feature headers + +The emitted code may have introduced another beta sub-client (a new property on class `BetaOperations`). It may have also added another enum value to the existing internal class `_FoundryFeaturesOptInKeys`. This means that the client library needs to set a new HTTP request header when making REST API calls to the service, to opt-in to the new service features which are still in preview. If that's the case, do the following: + +* Update the dictionary `_BETA_OPERATION_FEATURE_HEADERS` defined in `azure\ai\projects\models\_patch.py`, to include a new key-value pair to map the new beta sub-client name to the proper value from `_FoundryFeaturesOptInKeys`. If no new beta sub-client was introduced, but a new enum value was added to `_FoundryFeaturesOptInKeys`, you will need to update one of the existing key-value pairs in `_BETA_OPERATION_FEATURE_HEADERS` to a comma-separated join of multiple values from `_FoundryFeaturesOptInKeys`. + +* Do a similar change to the dictionary `EXPECTED_FOUNDRY_FEATURES` defined in the test file `tests\foundry_features_header\foundry_features_header_test_base.py`: add a new key-value pair if a new beta sub-client was introduced, or update an existing key-value pair to include the new enum value if no new beta sub-client was introduced. + +* Finally, look at the two files `azure\ai\projects\operations\_patch.py` and `azure\ai\projects\aio\operations\_patch.py`. They define the public `BetaOperations` classes for the sync and async clients. To support a new sub-client, you will need to add a new property to this class with the proper doc string. You will need to update the import statement at the top of the file to import the new sub-client class. And you will need to update `__all__` statement at the bottom of the file to include the new sub-client class name. Follow the examples you see there for `BetaDatasetsOperations` or `BetaSkillsOperations`. + +If a new enum value was added to `_AgentDefinitionOptInKeys`, please print a note on screen that mentions which value was added, and tell the user that a review is needed to make sure this new value is properly used. But otherwise continue on. + +Important: Under the `azure\ai\projects` folder, you are only allowed to edit Python source files that start with "_patch". If you see that changes are needed in other files, stop and report this to the user instead of making the changes yourself. + +--- + +## Step 10: Update samples and tests + +If there were any breaking changes in existing APIs, like class or method renames: +* update the patched code accordingly in the client library to reflect those changes. Changes should be made to Python source file names that start with "_patch", under the `azure\ai\projects` folder. +* update the samples accordingly to reflect those changes. Changes should be made under `sdk/ai/azure-ai-projects/samples` folder. +* update the tests accordingly to reflect those changes. Changes should be made under `sdk/ai/azure-ai-projects/tests` folder. + +--- + +## Step 11: Install package from sources + +In the folder `sdk\ai\azure-ai-projects`, run `pip install -e .` to install the package from sources. If there are any errors, stop and report the error to the user. Do not continue. + +--- + +## Step 12: Update CHANGELOG.md + +Use the **`azsdk-common-generate-sdk-locally`** skill's changelog capability (`azsdk_package_update_changelog_content`) to update `CHANGELOG.md` in the `sdk/ai/azure-ai-projects` folder with a summary of changes from the TypeSpec emit. Some guidelines to follow: +* Start by examining the public SDK API surface of the latest released version of the azure-ai-projects package. The source code for this version can be found in the Main branch of the `azure-sdk-for-python` repository, in the folder `sdk\ai\azure-ai-projects`. +* Then compare it to the public SDK API surface of current version in this topic branch. +* Look at the existing change log from the latest version (if exists) and edit or add to it to capture all the changes you see. If a change log does not exist for the current version at the top of `CHANGELOG.md`, create a new one. +* If a new method was added, there is no need to add the list of all new classes that define the inputs and output of the method. It's enough to mention that the new method was added. +* Show the user the proposed changelog entry and ask for confirmation or edits before saving. + +--- + +## Step 13: Commit and push + +Stage all changes (excluding file names that start with `.env`), commit, and push the topic branch: + +``` +git add -A -- ':!.env*' +git commit -m "Part 3: Additional edits" + +Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>" +git push -u origin +``` + +--- + +## Step 14: Create a Pull Request + +Create a draft PR from the **topic branch** to the **base branch** (recorded in Step 2): + +``` +gh pr create --draft --base --head --assignee @me --title "" --body "" +``` + +- **Title:** Use a descriptive title such as `[azure-ai-projects] Emit SDK from TypeSpec ()`. +- **Body:** Include which TypeSpec source was used and a summary of the changelog entry. + +You must show the user the resulting PR URL on screen when done, before you continue to the next step. + +Open a new tab in the default browser and navigate to the PR URL. + +--- + +## Step 15: Optionally run tests locally + +Prompt the user with this message: "Tests will run as part of the Pull Request. However, you can optionally run tests locally in a Python virtual environment, right now. It will take a few minutes. Do you want to run tests locally? (yes/no)" + +If the user answers "yes", run all tests from recordings. Follow these guidelines: +* Run tests in a local Python virtual environment. Create this virtual environment if it does not already exists: + ``` + python -m venv .venv + ``` + and activate it: + ``` + .venv\Scripts\activate + ``` +* Show test progress on screen, as tests are run. + + diff --git a/sdk/ai/azure-ai-projects/.github/skills/update-env-vars/.gitignore b/sdk/ai/azure-ai-projects/.github/skills/update-env-vars/.gitignore new file mode 100644 index 000000000000..c96a04f008ee --- /dev/null +++ b/sdk/ai/azure-ai-projects/.github/skills/update-env-vars/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/CHANGELOG.md b/sdk/ai/azure-ai-projects/CHANGELOG.md index d6a0253d9f0a..c67809ff4764 100644 --- a/sdk/ai/azure-ai-projects/CHANGELOG.md +++ b/sdk/ai/azure-ai-projects/CHANGELOG.md @@ -1,9 +1,67 @@ # Release History +## 2.2.0 (Unreleased) + +### Features Added + +* Support integration of external Agents (in preview). See new `ExternalAgentDefinition` class. +* New Agent tool in preview `FabricIQPreviewTool`. +* New Agent tool in preview `ToolboxSearchPreviewTool`. +* New optional string properties `description` and `name` added to Agent tools classes which did not have them before. +* New optional `tool_configs` added to Agent tool classes. +* New `.beta.datasets` sub-client with data generation job operations: `create_generation_job`, `get_generation_job`, `list_generation_jobs`, `cancel_generation_job`, `delete_generation_job`. +* New `.beta.models` sub-client to handle AI model weights: `list_versions`, `list`, `get`, `delete`, `update`, `pending_create_version`, `pending_upload`, `get_credentials`. +* New `.beta.routines` sub-client with routine operations: `create_or_update`, `get`, `enable`, `disable`, `list`, `delete`, `list_runs`, `dispatch`. +* New methods on `.beta.evaluators` for evaluator generation jobs: `create_generation_job`, `get_generation_job`, `list_generation_jobs`, `cancel_generation_job`, `delete_generation_job`. +* New methods on `.beta.agents` for code-based hosted agents: `create_version_from_code`, `download_code`. +* New methods on `.beta.agents` for optimization jobs: `create_optimization_job`, `get_optimization_job`, `list_optimization_jobs`, `cancel_optimization_job`, `list_optimization_candidates`. +* New methods on `.beta.memory_stores` to handle individual memory items:`.beta.memory_stores`: `get_memory`, `delete_memory`. +* New read-only property `content_hash` on `CodeConfiguration`, returning the SHA-256 hex digest of the uploaded code zip. +* 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_simpleqna_with_prompt_source.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()` 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 + +Breaking changes in beta methods: +* Required keyword `isolation_key` removed from `.beta.agents.create_session()` and `.beta.agents.delete_session()` methods. +* Argument `body` in methods `.beta.evaluation_taxonomies.create()` and `.beta.evaluation_taxonomies.update()` renamed to `taxonomy`. +* Argument `body` in method `.beta.skills.create_from_package()` renamed to `content`. + +Breaking changes in beta classes: +* Required property `isolation_key_source` removed from class `EntraAuthorizationScheme`. +* Renamed class `AgentEndpoint` to `AgentEndpointConfig`. +* Renamed class `DeleteSkillResponse` to `DeleteSkillResult`. +* Renamed class `SessionDirectoryListResponse` to `SessionDirectoryListResult`. +* Renamed class `SessionFileWriteResponse` to `SessionFileWriteResult`. +* Renamed class `SkillObject` to `SkillDetails`. +* Renamed class `Target` to `EvaluationTarget`. +* Renamed class `TargetConfig` to `RedTeamTargetConfig`. +* Removed class `FabricIQPreviewToolParameters`. +* Removed class `WorkIQPreviewToolParameters`. + +### Bugs Fixed + +* Fixed telemetry instrumentor to correctly call is_recording() as a method on spans, ensuring non-recording spans are properly skipped (e.g., when sampling is configured) ([GitHub issue 46544](https://github.com/Azure/azure-sdk-for-python/issues/46544)). + +### Sample updates + +* Added Hosted Agent creation samples `sample_create_hosted_agent.py` and `sample_create_hosted_agent_async.py`, demonstrating hosted agent version creation and retrieval with `AIProjectClient`. +* Added Hosted Agent code-upload samples `sample_create_hosted_agent_from_code.py` and `sample_create_hosted_agent_from_code_async.py`, demonstrating uploading a code package (zip) as a new hosted agent version. +* 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 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` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + * `sample_models_create_and_poll.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) ### Features Added +* New `WorkIQPreviewTool`. * `get_openai_client()` on `AIProjectClient` now takes an optional input argument `agent_name`. If provided, the returned OpenAI client will use a base URL of Agent endpoint instead of Foundry Project endpoint. As Agent endpoints are a preview feature, you need to set `allow_preview=True` on the `AIProjectClient` constructor. diff --git a/sdk/ai/azure-ai-projects/README.md b/sdk/ai/azure-ai-projects/README.md index b2f754b91fd2..44365a930a5f 100644 --- a/sdk/ai/azure-ai-projects/README.md +++ b/sdk/ai/azure-ai-projects/README.md @@ -1,6 +1,6 @@ # Azure AI Projects client library for Python -The AI Projects client library (in preview) is part of the Microsoft Foundry SDK, and provides easy access to +The AI Projects client library is part of the Microsoft Foundry SDK, and provides easy access to resources in your Microsoft Foundry Project. Use it to: * **Create and run Agents** using methods on the `.agents` client property. @@ -13,6 +13,7 @@ resources in your Microsoft Foundry Project. Use it to: * Browser Automation (Preview) * Code Interpreter * Computer Use (Preview) + * Fabric IQ (Preview) * File Search * Function Tool * Image Generation @@ -21,8 +22,10 @@ resources in your Microsoft Foundry Project. Use it to: * Microsoft SharePoint (Preview) * Model Context Protocol (MCP) * OpenAPI + * Toolbox Search (Preview) * Web Search * Web Search (Preview) + * Work IQ (Preview) * **Get an OpenAI client** using `.get_openai_client()` method to run Responses, Conversations, Evaluations and Fine-Tuning operations with your Agent. * **Manage memory stores (preview)** for Agent conversations, using `.beta.memory_stores` operations. * **Explore additional evaluation tools (some in preview)** to assess the performance of your generative AI application, using `.evaluation_rules`, @@ -32,6 +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` 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). @@ -55,8 +59,7 @@ To report an issue with the client library, or request additional features, plea * An [Azure subscription][azure_sub]. * A [project in Microsoft Foundry](https://learn.microsoft.com/azure/foundry/how-to/create-projects). * A Foundry project endpoint URL of the form `https://your-ai-services-account-name.services.ai.azure.com/api/projects/your-project-name`. It can be found in your Microsoft Foundry Project home page. Below we will assume the environment variable `FOUNDRY_PROJECT_ENDPOINT` was defined to hold this value. -* To authenticate using API key, you will need the "Project API key" as shown in your Microsoft Foundry Project home page. -* To authenticate using Entra ID, your application needs an object that implements the [TokenCredential](https://learn.microsoft.com/python/api/azure-core/azure.core.credentials.tokencredential) interface. Code samples here use [DefaultAzureCredential](https://learn.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential). To get that working, you will need: +* Client authentication is done using Entra ID. To authenticate, your application needs an object that implements the [TokenCredential](https://learn.microsoft.com/python/api/azure-core/azure.core.credentials.tokencredential) interface. Code samples here use [DefaultAzureCredential](https://learn.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential). To get that working, you will need: * An appropriate role assignment. See [Role-based access control in Microsoft Foundry portal](https://learn.microsoft.com/azure/foundry/concepts/rbac-foundry). Role assignment can be done via the "Access Control (IAM)" tab of your Azure AI Project resource in the Azure portal. * [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) installed. * You are logged into your Azure account by running `az login`. @@ -116,12 +119,12 @@ async with ( For comprehensive examples covering Agents, tool usage, evaluation, fine-tuning, datasets, indexes, and more, see: -* **[Microsoft Foundry Agents overview](https://learn.microsoft.com/azure/foundry/agents/overview)** — concepts, setup, and quickstarts. +* **[Microsoft Foundry Agents overview](https://learn.microsoft.com/azure/foundry/agents/overview)** — concepts, setup, and quick-starts. * **[Runtime components](https://learn.microsoft.com/azure/foundry/agents/concepts/runtime-components?tabs=python)** — deep-dive into agent architecture. * **[Tool catalog](https://learn.microsoft.com/azure/foundry/agents/concepts/tool-catalog)** — all available tools and agent capabilities. * **[SDK samples folder][samples]** — fully runnable Python code for synchronous and asynchronous clients covering all operations below. -The sections below cover SDK-specific behaviours (authentication variants, exception handling, logging, tracing) that are not documented in the above Learn pages. +The sections below cover SDK-specific behaviors (authentication variants, exception handling, logging, tracing) that are not documented in the above Learn pages. ### Performing Responses operations using OpenAI client @@ -164,6 +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`, `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/` | @@ -179,219 +183,13 @@ For product guidance, see: For SDK usage examples in this package, see `samples/hosted_agents/`, including CRUD, file upload/download, and skills scenarios. -## Tracing +## Client-side tracing -### Experimental Feature Gate +See [Add client-side tracing to Foundry agents (preview)](https://learn.microsoft.com/azure/foundry/observability/how-to/trace-agent-client-side?tabs=python). -**Important:** GenAI tracing instrumentation is an experimental preview feature. Spans, attributes, and events may be modified in future versions. To use it, you must explicitly opt in by setting the environment variable: +**Important:** GenAI tracing instrumentation is an experimental preview feature. Spans, attributes, and events may be modified in future versions. -```bash -AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true -``` - -This environment variable must be set before calling `AIProjectInstrumentor().instrument()`. If the environment variable is not set or is set to any value other than `true` (case-insensitive), tracing instrumentation will not be enabled and a warning will be logged. - -Only enable this feature after reviewing your requirements and understanding that the tracing behavior may change in future versions. - -### Getting Started with Tracing - -You can add an Application Insights Azure resource to your Microsoft Foundry project. See the Tracing tab in your Microsoft Foundry project. If one was enabled, you can get the Application Insights connection string, configure your AI Projects client, and observe traces in Azure Monitor. Typically, you might want to start tracing before you create a client or Agent. - -For tracing concepts in Microsoft Foundry, see [Trace an agent](https://learn.microsoft.com/azure/foundry/observability/concepts/trace-agent-concept). - -### Installation - -Make sure to install OpenTelemetry and the Azure SDK tracing plugin via - -```bash -pip install "azure-ai-projects>=2.0.0b4" opentelemetry-sdk azure-core-tracing-opentelemetry azure-monitor-opentelemetry -``` - -You will also need an exporter to send telemetry to your observability backend. You can print traces to the console or use a local viewer such as [Aspire Dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone?tabs=bash). - -To connect to Aspire Dashboard or another OpenTelemetry compatible backend, install OTLP exporter: - -```bash -pip install opentelemetry-exporter-otlp -``` - -### How to enable tracing - -**Remember:** Before enabling tracing, ensure you have set the `AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true` environment variable as described in the [Experimental Feature Gate](#experimental-feature-gate) section. - -Here is a code sample that shows how to enable Azure Monitor tracing: - - - -```python -# Enable Azure Monitor tracing -application_insights_connection_string = project_client.telemetry.get_application_insights_connection_string() -configure_azure_monitor(connection_string=application_insights_connection_string) -``` - - - -You may also want to create a span for your scenario: - - - -```python -tracer = trace.get_tracer(__name__) -scenario = os.path.basename(__file__) - -with tracer.start_as_current_span(scenario): -``` - - - -See the full sample in file `\agents\telemetry\sample_agent_basic_with_azure_monitor_tracing.py` in the [Samples][samples] folder. - -**Note:** In order to view the traces in the Microsoft Foundry portal, the agent ID should be passed in as part of the response generation request. - -In addition, you might find it helpful to see the tracing logs in the console. Remember to set `AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true` before running the following code: - - - -```python -# Setup tracing to console -# Requires opentelemetry-sdk -span_exporter = ConsoleSpanExporter() -tracer_provider = TracerProvider() -tracer_provider.add_span_processor(SimpleSpanProcessor(span_exporter)) -trace.set_tracer_provider(tracer_provider) -tracer = trace.get_tracer(__name__) - -# Enable instrumentation with content tracing -AIProjectInstrumentor().instrument() -``` - - - -See the full sample in file `\agents\telemetry\sample_agent_basic_with_console_tracing.py` in the [Samples][samples] folder. - -### Enabling trace context propagation - -Trace context propagation allows client-side spans generated by the Projects SDK to be correlated with server-side spans from Azure OpenAI and other Azure services. When enabled, the SDK automatically injects W3C Trace Context headers (`traceparent` and `tracestate`) into HTTP requests made by OpenAI clients obtained via `get_openai_client()`. - -This feature ensures that all operations within a distributed trace share the same trace ID, providing end-to-end visibility across your application and Azure services in your observability backend (such as Azure Monitor). - -Trace context propagation is **enabled by default** when tracing is enabled (for example through `configure_azure_monitor` or the `AIProjectInstrumentor().instrument()` call). To disable it, set the `AZURE_TRACING_GEN_AI_ENABLE_TRACE_CONTEXT_PROPAGATION` environment variable to `false`, or pass `enable_trace_context_propagation=False` to the `AIProjectInstrumentor().instrument()` call. - -**When does the change take effect?** -- Changes to `enable_trace_context_propagation` (whether via `instrument()` or the environment variable) only affect OpenAI clients obtained via `get_openai_client()` **after** the change is applied. Previously acquired clients are unaffected. -- To apply the new setting to all clients, call `AIProjectInstrumentor().instrument(enable_trace_context_propagation=)` before acquiring your OpenAI clients, or re-acquire the clients after making the change. - -**Security and Privacy Considerations:** -- **Trace IDs are sent to external services**: The `traceparent` and `tracestate` headers from your client-side originating spans are injected into requests sent to service. This enables end-to-end distributed tracing, but note that the trace identifier may be shared beyond the initial API call. -- **Enabled by Default**: If you have privacy or compliance requirements that prohibit sharing trace identifiers with services, disable trace context propagation by setting `enable_trace_context_propagation=False` or the environment variable to `false`. - -#### Controlling baggage propagation - -When trace context propagation is enabled, you can separately control whether the baggage header is included. By default, only `traceparent` and `tracestate` headers are propagated. To also include the `baggage` header, set the `AZURE_TRACING_GEN_AI_TRACE_CONTEXT_PROPAGATION_INCLUDE_BAGGAGE` environment variable to `true`: - -If no value is provided for the `enable_baggage_propagation` parameter with the `AIProjectInstrumentor.instrument()` call and the environment variable is not set, the value defaults to `false` and baggage is not included. - -**Note:** The `enable_baggage_propagation` flag is evaluated dynamically on each request, so changes take effect **immediately** for all clients that have the trace context propagation hook registered. However, the hook is only registered on clients acquired via `get_openai_client()` **while trace context propagation was enabled**. Clients acquired when trace context propagation was disabled will never propagate baggage, regardless of the `enable_baggage_propagation` value. - -**Why is baggage propagation separate?** - -The baggage header can contain arbitrary key-value pairs added anywhere in your application's trace context. Unlike trace IDs (which are randomly generated identifiers), baggage may contain: - -- User identifiers or session information -- Authentication tokens or credentials -- Business-specific data or metadata -- Personally identifiable information (PII) - -Baggage is automatically propagated through your entire application's call chain, meaning data added in one part of your application will be included in requests to Azure OpenAI unless explicitly controlled. - -**Important Security Considerations:** - -- **Review Baggage Contents**: Before enabling baggage propagation, audit what data your application (and any third-party libraries) adds to OpenTelemetry baggage. -- **Sensitive Data Risk**: Baggage is sent to Azure OpenAI and may be logged or processed by Microsoft services. Never add sensitive information to baggage when baggage propagation is enabled. -- **Opt-in by Design**: Baggage propagation is disabled by default (even when trace context propagation is enabled) to prevent accidental exposure of sensitive data. -- **Minimal Propagation**: `traceparent` and `tracestate` headers are generally sufficient for distributed tracing. Only enable baggage propagation if your specific observability requirements demand it. - -### Enabling content recording - -Content recording controls whether message contents and tool call related details, such as parameters and return values, are captured with the traces. This data may include sensitive user information. - -To enable content recording, set the `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` environment variable to `true`. If the environment variable is not set and no value is provided with the `AIProjectInstrumentor().instrument()` call for the content recording parameter, content recording defaults to `false`. - -**Important:** The environment variable only controls content recording for built-in traces. When you use custom tracing decorators on your own functions, all parameters and return values are always traced. - -### Disabling automatic instrumentation - -The AI Projects client library automatically instruments OpenAI responses and conversations operations through `AiProjectInstrumentation`. You can disable this instrumentation by setting the environment variable `AZURE_TRACING_GEN_AI_INSTRUMENT_RESPONSES_API` to `false`. If the environment variable is not set, the responses and conversations APIs will be instrumented by default. - -### Tracing Binary Data - -Binary data are images and files sent to the service as input messages. When you enable content recording (`OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` set to `true`), by default you only trace file IDs and filenames. To enable full binary data tracing, set `AZURE_TRACING_GEN_AI_INCLUDE_BINARY_DATA` to `true`. In this case: - -* **Images**: Image URLs (including data URIs with base64-encoded content) are included -* **Files**: File data is included if sent via the API - -**Important:** Binary data can contain sensitive information and may significantly increase trace size. Some trace backends and tracing implementations may have limitations on the maximum size of trace data that can be sent to and/or supported by the backend. Ensure your observability backend and tracing implementation support the expected trace payload sizes when enabling binary data tracing. - -### How to trace your own functions - -The decorator `trace_function` is provided for tracing your own function calls using OpenTelemetry. By default the function name is used as the name for the span. Alternatively you can provide the name for the span as a parameter to the decorator. - -**Note:** The `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` environment variable does not affect custom function tracing. When you use the `trace_function` decorator, all parameters and return values are always traced by default. - -This decorator handles various data types for function parameters and return values, and records them as attributes in the trace span. The supported data types include: - -* Basic data types: str, int, float, bool -* Collections: list, dict, tuple, set - * Special handling for collections: - * If a collection (list, dict, tuple, set) contains nested collections, the entire collection is converted to a string before being recorded as an attribute. - * Sets and dictionaries are always converted to strings to ensure compatibility with span attributes. - -Object types are omitted, and the corresponding parameter is not traced. - -The parameters are recorded in attributes `code.function.parameter.` and the return value is recorder in attribute `code.function.return.value` - -#### Adding custom attributes to spans - -You can add custom attributes to spans by creating a custom span processor. Here's how to define one: - - - -```python -class CustomAttributeSpanProcessor(SpanProcessor): - def __init__(self) -> None: - pass - - def on_start(self, span: Span, parent_context=None): - # Add this attribute to all spans - span.set_attribute("trace_sample.sessionid", "123") - - # Add another attribute only to create_thread spans - if span.name == "create_thread": - span.set_attribute("trace_sample.create_thread.context", "abc") - - def on_end(self, span: ReadableSpan): - # Clean-up logic can be added here if necessary - pass -``` - - - -Then add the custom span processor to the global tracer provider: - - - -```python -provider = cast(TracerProvider, trace.get_tracer_provider()) -provider.add_span_processor(CustomAttributeSpanProcessor()) -``` - - - -See the full sample in file `\agents\telemetry\sample_agent_basic_with_console_tracing_custom_attributes.py` in the [Samples][samples] folder. - -### Additional resources - -For more information see [Agent tracing overview (preview)](https://learn.microsoft.com/azure/foundry/observability/concepts/trace-agent-concept). +Samples can be found in the sub-folders `agents/telemetry` and `telemetry` in the [Samples][samples] folder. ## Troubleshooting diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index f6caeb745b80..7e6e38b214d3 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -10,15 +10,20 @@ "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.AgentEndpoint": "Azure.AI.Projects.AgentEndpoint", "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", "azure.ai.projects.models.AgentObjectVersions": "Azure.AI.Projects.AgentObject.versions.anonymous", "azure.ai.projects.models.AgentSessionResource": "Azure.AI.Projects.AgentSessionResource", + "azure.ai.projects.models.AgentsPagedResultOptimizationCandidate": "Azure.AI.Projects.AgentsPagedResult", "azure.ai.projects.models.EvaluationTaxonomyInput": "Azure.AI.Projects.EvaluationTaxonomyInput", "azure.ai.projects.models.AgentTaxonomyInput": "Azure.AI.Projects.AgentTaxonomyInput", "azure.ai.projects.models.AgentVersionDetails": "Azure.AI.Projects.AgentVersionObject", @@ -28,8 +33,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", @@ -41,7 +47,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", @@ -56,6 +62,8 @@ "azure.ai.projects.models.BrowserAutomationPreviewTool": "Azure.AI.Projects.BrowserAutomationPreviewTool", "azure.ai.projects.models.BrowserAutomationToolConnectionParameters": "Azure.AI.Projects.BrowserAutomationToolConnectionParameters", "azure.ai.projects.models.BrowserAutomationToolParameters": "Azure.AI.Projects.BrowserAutomationToolParameters", + "azure.ai.projects.models.CandidateDeployConfig": "Azure.AI.Projects.CandidateDeployConfig", + "azure.ai.projects.models.CandidateResults": "Azure.AI.Projects.CandidateResults", "azure.ai.projects.models.CaptureStructuredOutputsTool": "Azure.AI.Projects.CaptureStructuredOutputsTool", "azure.ai.projects.models.ChartCoordinate": "Azure.AI.Projects.ChartCoordinate", "azure.ai.projects.models.MemoryItem": "Azure.AI.Projects.MemoryItem", @@ -81,6 +89,9 @@ "azure.ai.projects.models.EvaluationRuleAction": "Azure.AI.Projects.EvaluationRuleAction", "azure.ai.projects.models.ContinuousEvaluationRuleAction": "Azure.AI.Projects.ContinuousEvaluationRuleAction", "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.Trigger": "Azure.AI.Projects.Trigger", "azure.ai.projects.models.CronTrigger": "Azure.AI.Projects.CronTrigger", "azure.ai.projects.models.CustomCredential": "Azure.AI.Projects.CustomCredential", @@ -90,24 +101,43 @@ "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.DataGenerationJobOutputOptions": "Azure.AI.Projects.DataGenerationJobOutputOptions", + "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.DatasetItem": "Azure.AI.Projects.DatasetItem", + "azure.ai.projects.models.DatasetRef": "Azure.AI.Projects.DatasetRef", + "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", + "azure.ai.projects.models.DeleteMemoryResult": "Azure.AI.Projects.DeleteMemoryResponse", "azure.ai.projects.models.DeleteMemoryStoreResult": "Azure.AI.Projects.DeleteMemoryStoreResponse", - "azure.ai.projects.models.DeleteSkillResponse": "Azure.AI.Projects.DeleteSkillResponse", + "azure.ai.projects.models.DeleteSkillResult": "Azure.AI.Projects.DeleteSkillResponse", "azure.ai.projects.models.Deployment": "Azure.AI.Projects.Deployment", + "azure.ai.projects.models.Dimension": "Azure.AI.Projects.Dimension", + "azure.ai.projects.models.DispatchRoutineResult": "Azure.AI.Projects.DispatchRoutineResponse", "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.IsolationKeySource": "Azure.AI.Projects.IsolationKeySource", "azure.ai.projects.models.EntraIsolationKeySource": "Azure.AI.Projects.EntraIsolationKeySource", "azure.ai.projects.models.EvalResult": "Azure.AI.Projects.EvalResult", + "azure.ai.projects.models.EvalRunOutputItemResult": "Azure.AI.Projects.EvalRunOutputItemResult", "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.EvaluationCriterion": "Azure.AI.Projects.EvaluationCriterion", "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", @@ -117,19 +147,31 @@ "azure.ai.projects.models.ScheduleTask": "Azure.AI.Projects.ScheduleTask", "azure.ai.projects.models.EvaluationScheduleTask": "Azure.AI.Projects.EvaluationScheduleTask", "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", + "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.ExternalAgentDefinition": "Azure.AI.Projects.ExternalAgentDefinition", "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", "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", "azure.ai.projects.models.FunctionTool": "OpenAI.FunctionTool", + "azure.ai.projects.models.RoutineTrigger": "Azure.AI.Projects.RoutineTrigger", + "azure.ai.projects.models.GitHubIssueOpenedRoutineTrigger": "Azure.AI.Projects.GitHubIssueOpenedRoutineTrigger", "azure.ai.projects.models.HeaderIsolationKeySource": "Azure.AI.Projects.HeaderIsolationKeySource", "azure.ai.projects.models.TelemetryEndpointAuth": "Azure.AI.Projects.TelemetryEndpointAuth", "azure.ai.projects.models.HeaderTelemetryEndpointAuth": "Azure.AI.Projects.HeaderTelemetryEndpointAuth", @@ -147,8 +189,15 @@ "azure.ai.projects.models.InsightScheduleTask": "Azure.AI.Projects.InsightScheduleTask", "azure.ai.projects.models.InsightsMetadata": "Azure.AI.Projects.InsightsMetadata", "azure.ai.projects.models.InsightSummary": "Azure.AI.Projects.InsightSummary", + "azure.ai.projects.models.RoutineDispatchPayload": "Azure.AI.Projects.RoutineDispatchPayload", + "azure.ai.projects.models.InvokeAgentInvocationsApiDispatchPayload": "Azure.AI.Projects.InvokeAgentInvocationsApiDispatchPayload", + "azure.ai.projects.models.RoutineAction": "Azure.AI.Projects.RoutineAction", + "azure.ai.projects.models.InvokeAgentInvocationsApiRoutineAction": "Azure.AI.Projects.InvokeAgentInvocationsApiRoutineAction", + "azure.ai.projects.models.InvokeAgentResponsesApiDispatchPayload": "Azure.AI.Projects.InvokeAgentResponsesApiDispatchPayload", + "azure.ai.projects.models.InvokeAgentResponsesApiRoutineAction": "Azure.AI.Projects.InvokeAgentResponsesApiRoutineAction", "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", @@ -168,9 +217,14 @@ "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.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", "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", @@ -183,13 +237,25 @@ "azure.ai.projects.models.OpenApiProjectConnectionAuthDetails": "Azure.AI.Projects.OpenApiProjectConnectionAuthDetails", "azure.ai.projects.models.OpenApiProjectConnectionSecurityScheme": "Azure.AI.Projects.OpenApiProjectConnectionSecurityScheme", "azure.ai.projects.models.OpenApiTool": "Azure.AI.Projects.OpenApiTool", + "azure.ai.projects.models.OptimizationAgentDefinition": "Azure.AI.Projects.OptimizationAgentDefinition", + "azure.ai.projects.models.OptimizationAgentSkill": "Azure.AI.Projects.OptimizationAgentSkill", + "azure.ai.projects.models.OptimizationCandidate": "Azure.AI.Projects.OptimizationCandidate", + "azure.ai.projects.models.OptimizationJob": "Azure.AI.Projects.OptimizationJob", + "azure.ai.projects.models.OptimizationJobInputs": "Azure.AI.Projects.OptimizationJobInputs", + "azure.ai.projects.models.OptimizationJobProgress": "Azure.AI.Projects.OptimizationJobProgress", + "azure.ai.projects.models.OptimizationJobResult": "Azure.AI.Projects.OptimizationJobResult", + "azure.ai.projects.models.OptimizationOptions": "Azure.AI.Projects.OptimizationOptions", + "azure.ai.projects.models.OptimizationTaskResult": "Azure.AI.Projects.OptimizationTaskResult", "azure.ai.projects.models.TelemetryEndpoint": "Azure.AI.Projects.TelemetryEndpoint", "azure.ai.projects.models.OtlpTelemetryEndpoint": "Azure.AI.Projects.OtlpTelemetryEndpoint", "azure.ai.projects.models.PendingUploadRequest": "Azure.AI.Projects.PendingUploadRequest", "azure.ai.projects.models.PendingUploadResponse": "Azure.AI.Projects.PendingUploadResponse", + "azure.ai.projects.models.ProceduralMemoryItem": "Azure.AI.Projects.ProceduralMemoryItem", "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", @@ -198,22 +264,29 @@ "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.Routine": "Azure.AI.Projects.Routine", + "azure.ai.projects.models.RoutineRun": "Azure.AI.Projects.RoutineRun", + "azure.ai.projects.models.RoutineRunDiagnostics": "Azure.AI.Projects.RoutineRunDiagnostics", + "azure.ai.projects.models.RubricBasedEvaluatorDefinition": "Azure.AI.Projects.RubricBasedEvaluatorDefinition", "azure.ai.projects.models.SASCredentials": "Azure.AI.Projects.SASCredentials", "azure.ai.projects.models.Schedule": "Azure.AI.Projects.Schedule", + "azure.ai.projects.models.ScheduleRoutineTrigger": "Azure.AI.Projects.ScheduleRoutineTrigger", "azure.ai.projects.models.ScheduleRun": "Azure.AI.Projects.ScheduleRun", "azure.ai.projects.models.SessionDirectoryEntry": "Azure.AI.Projects.SessionDirectoryEntry", - "azure.ai.projects.models.SessionDirectoryListResponse": "Azure.AI.Projects.SessionDirectoryListResponse", - "azure.ai.projects.models.SessionFileWriteResponse": "Azure.AI.Projects.SessionFileWriteResponse", + "azure.ai.projects.models.SessionDirectoryListResult": "Azure.AI.Projects.SessionDirectoryListResponse", + "azure.ai.projects.models.SessionFileWriteResult": "Azure.AI.Projects.SessionFileWriteResponse", "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.SkillObject": "Azure.AI.Projects.SkillObject", + "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", "azure.ai.projects.models.SpecificApplyPatchParam": "OpenAI.SpecificApplyPatchParam", "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", @@ -221,8 +294,10 @@ "azure.ai.projects.models.TextResponseFormatJsonObject": "OpenAI.TextResponseFormatConfigurationResponseFormatJsonObject", "azure.ai.projects.models.TextResponseFormatJsonSchema": "OpenAI.TextResponseFormatJsonSchema", "azure.ai.projects.models.TextResponseFormatText": "OpenAI.TextResponseFormatConfigurationResponseFormatText", + "azure.ai.projects.models.TimerRoutineTrigger": "Azure.AI.Projects.TimerRoutineTrigger", "azure.ai.projects.models.ToolboxObject": "Azure.AI.Projects.ToolboxObject", "azure.ai.projects.models.ToolboxPolicies": "Azure.AI.Projects.ToolboxPolicies", + "azure.ai.projects.models.ToolboxSearchPreviewTool": "Azure.AI.Projects.ToolboxSearchPreviewTool", "azure.ai.projects.models.ToolboxVersionObject": "Azure.AI.Projects.ToolboxVersionObject", "azure.ai.projects.models.ToolChoiceAllowed": "OpenAI.ToolChoiceAllowed", "azure.ai.projects.models.ToolChoiceCodeInterpreter": "OpenAI.ToolChoiceCodeInterpreter", @@ -234,8 +309,14 @@ "azure.ai.projects.models.ToolChoiceMCP": "OpenAI.ToolChoiceMCP", "azure.ai.projects.models.ToolChoiceWebSearchPreview": "OpenAI.ToolChoiceWebSearchPreview", "azure.ai.projects.models.ToolChoiceWebSearchPreview20250311": "OpenAI.ToolChoiceWebSearchPreview20250311", + "azure.ai.projects.models.ToolConfig": "Azure.AI.Projects.ToolConfig", "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", "azure.ai.projects.models.VersionIndicator": "Azure.AI.Projects.VersionIndicator", @@ -249,7 +330,6 @@ "azure.ai.projects.models.WeeklyRecurrenceSchedule": "Azure.AI.Projects.WeeklyRecurrenceSchedule", "azure.ai.projects.models.WorkflowAgentDefinition": "Azure.AI.Projects.WorkflowAgentDefinition", "azure.ai.projects.models.WorkIQPreviewTool": "Azure.AI.Projects.WorkIQPreviewTool", - "azure.ai.projects.models.WorkIQPreviewToolParameters": "Azure.AI.Projects.WorkIQPreviewToolParameters", "azure.ai.projects.models.AgentObjectType": "Azure.AI.Projects.AgentObjectType", "azure.ai.projects.models.AgentKind": "Azure.AI.Projects.AgentKind", "azure.ai.projects.models.ToolType": "OpenAI.ToolType", @@ -267,6 +347,7 @@ "azure.ai.projects.models.ContainerSkillType": "OpenAI.ContainerSkillType", "azure.ai.projects.models.SearchContextSize": "OpenAI.SearchContextSize", "azure.ai.projects.models.AgentProtocol": "Azure.AI.Projects.AgentProtocol", + "azure.ai.projects.models.CodeDependencyResolution": "Azure.AI.Projects.CodeDependencyResolution", "azure.ai.projects.models.TelemetryEndpointKind": "Azure.AI.Projects.TelemetryEndpointKind", "azure.ai.projects.models.TelemetryDataKind": "Azure.AI.Projects.TelemetryDataKind", "azure.ai.projects.models.TelemetryEndpointAuthType": "Azure.AI.Projects.TelemetryEndpointAuthType", @@ -283,6 +364,10 @@ "azure.ai.projects.models.AgentSessionStatus": "Azure.AI.Projects.AgentSessionStatus", "azure.ai.projects.models.PageOrder": "Azure.AI.Projects.PageOrder", "azure.ai.projects.models.SessionLogEventType": "Azure.AI.Projects.SessionLogEventType", + "azure.ai.projects.models.EvalRunOutputItemResultStatus": "Azure.AI.Projects.EvalRunOutputItemResultStatus", + "azure.ai.projects.models.OptimizationStrategy": "Azure.AI.Projects.OptimizationStrategy", + "azure.ai.projects.models.OptimizationMode": "Azure.AI.Projects.OptimizationMode", + "azure.ai.projects.models.JobStatus": "Azure.AI.Projects.JobStatus", "azure.ai.projects.models.EvaluationTaxonomyInputType": "Azure.AI.Projects.EvaluationTaxonomyInputType", "azure.ai.projects.models.RiskCategory": "Azure.AI.Projects.RiskCategory", "azure.ai.projects.models.EvaluatorType": "Azure.AI.Projects.EvaluatorType", @@ -290,6 +375,8 @@ "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.PendingUploadType": "Azure.AI.Projects.PendingUploadType", + "azure.ai.projects.models.EvaluatorGenerationJobSourceType": "Azure.AI.Projects.EvaluatorGenerationJobSourceType", "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", @@ -298,18 +385,32 @@ "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.AttackStrategy": "Azure.AI.Projects.AttackStrategy", + "azure.ai.projects.models.RoutineTriggerType": "Azure.AI.Projects.RoutineTriggerType", + "azure.ai.projects.models.RoutineActionType": "Azure.AI.Projects.RoutineActionType", + "azure.ai.projects.models.RoutineRunPhase": "Azure.AI.Projects.RoutineRunPhase", + "azure.ai.projects.models.RoutineAttemptSource": "Azure.AI.Projects.RoutineAttemptSource", + "azure.ai.projects.models.RoutineDispatchPayloadType": "Azure.AI.Projects.RoutineDispatchPayloadType", "azure.ai.projects.models.ScheduleProvisioningStatus": "Azure.AI.Projects.ScheduleProvisioningStatus", "azure.ai.projects.models.TriggerType": "Azure.AI.Projects.TriggerType", "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", "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/assets.json b/sdk/ai/azure-ai-projects/assets.json index 87ee354cd9f9..cd6eb8ff3d18 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_64257c2deb" + "Tag": "python/ai/azure-ai-projects_021c7decd3" } diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py index 950bfaf73334..8b68c0515aec 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py @@ -24,6 +24,86 @@ logger = logging.getLogger(__name__) +# --------------------------------------------------------------------------- +# Shared helpers used by both the sync and async AIProjectClient.get_openai_client() +# implementations. Defined at module level so the async client can import and reuse +# them without duplicating the logic. +# --------------------------------------------------------------------------- + + +def _resolve_openai_base_url(config: Any, agent_name: Optional[str], kwargs: dict) -> str: + """Resolve the base URL for the (Async)OpenAI client. + + :param config: Generated client configuration carrying ``endpoint`` and ``allow_preview``. + :type config: Any + :param agent_name: Optional hosted-agent name. + :type agent_name: str or None + :param kwargs: Caller keyword arguments; ``base_url`` is popped when present. + :type kwargs: dict + :return: The base URL to use for the (Async)OpenAI client. + :rtype: str + :raises ValueError: If ``agent_name`` is provided but ``allow_preview=True`` was not set. + """ + if "base_url" in kwargs: + return kwargs.pop("base_url") + if agent_name is not None: + if config.allow_preview: + return config.endpoint.rstrip("/") + f"/agents/{agent_name}/endpoint/protocols/openai" + raise ValueError( + "Calling `get_openai_client` method with an `agent_name` requires you to set `allow_preview=True`" + "\nwhen constructing the AIProjectClient. Note that preview features are under development and " + "\nsubject to change. They should not be used in production environments." + ) + return config.endpoint.rstrip("/") + "/openai/v1" + + +def _resolve_openai_query_params(config: Any, agent_name: Optional[str], kwargs: dict) -> dict: + """Build the ``default_query`` dict for the (Async)OpenAI client. + + :param config: Generated client configuration carrying ``api_version``. + :type config: Any + :param agent_name: Optional hosted-agent name. + :type agent_name: str or None + :param kwargs: Caller keyword arguments; ``default_query`` is popped when present. + :type kwargs: dict + :return: Query parameters to forward to the (Async)OpenAI client. + :rtype: dict + """ + default_query = dict[str, str](kwargs.pop("default_query", None) or {}) + if agent_name is not None and "api-version" not in default_query: + default_query["api-version"] = config.api_version + return default_query + + +def _resolve_openai_default_headers(agent_name: Optional[str], kwargs: dict) -> dict: + """Build the ``default_headers`` dict for the (Async)OpenAI client. + + :param agent_name: Optional hosted-agent name. + :type agent_name: str or None + :param kwargs: Caller keyword arguments; ``default_headers`` is popped when present. + :type kwargs: dict + :return: Headers to forward to the (Async)OpenAI client. + :rtype: dict + """ + default_headers = dict[str, str](kwargs.pop("default_headers", None) or {}) + if agent_name is not None and not _has_header_case_insensitive(default_headers, _FOUNDRY_FEATURES_HEADER_NAME): + default_headers[_FOUNDRY_FEATURES_HEADER_NAME] = _BETA_OPERATION_FEATURE_HEADERS["agents"] + return default_headers + + +def _build_openai_user_agent(custom_user_agent: Optional[str], openai_default_user_agent: str) -> str: + """Build the SDK-prefixed User-Agent string for the (Async)OpenAI client. + + :param custom_user_agent: Caller-supplied user_agent kwarg captured at construction time. + :type custom_user_agent: str or None + :param openai_default_user_agent: The OpenAI client's own default user-agent. + :type openai_default_user_agent: str + :return: Combined User-Agent string. + :rtype: str + """ + return "-".join(ua for ua in [custom_user_agent, "AIProjectClient"] if ua) + " " + openai_default_user_agent + + class AIProjectClient(AIProjectClientGenerated): # pylint: disable=too-many-instance-attributes """AIProjectClient. @@ -101,6 +181,35 @@ def __init__( self.telemetry = TelemetryOperations(self) # type: ignore + def _get_openai_api_key(self, kwargs: dict): + """Resolve the API key for the OpenAI client. + + :param kwargs: Caller keyword arguments; ``api_key`` is popped when present. + :type kwargs: dict + :return: The API key string or a bearer-token-provider callable. + :rtype: str or Callable + """ + if "api_key" in kwargs: + return kwargs.pop("api_key") + return get_bearer_token_provider( + self._config.credential, # pylint: disable=protected-access + "https://ai.azure.com/.default", + ) + + def _get_openai_http_client(self, kwargs: dict): + """Resolve the HTTP transport client for the OpenAI client. + + :param kwargs: Caller keyword arguments; ``http_client`` is popped when present. + :type kwargs: dict + :return: An httpx.Client instance configured with logging transport, or ``None``. + :rtype: httpx.Client or None + """ + if "http_client" in kwargs: + return kwargs.pop("http_client") + if self._console_logging_enabled: + return httpx.Client(transport=_OpenAILoggingTransport()) + return None + @distributed_trace def get_openai_client(self, *, agent_name: Optional[str] = None, **kwargs: Any) -> OpenAI: """Get an authenticated OpenAI client from the `openai` package. @@ -131,51 +240,17 @@ def get_openai_client(self, *, agent_name: Optional[str] = None, **kwargs: Any) kwargs = kwargs.copy() if kwargs else {} - # Allow caller to override base_url - if "base_url" in kwargs: - base_url = kwargs.pop("base_url") - elif agent_name is not None: - if self._config.allow_preview: - base_url = ( - self._config.endpoint.rstrip("/") + f"/agents/{agent_name}/endpoint/protocols/openai" - ) # pylint: disable=protected-access - else: - raise ValueError( - "Calling `get_openai_client` method with an `agent_name` requires you to set `allow_preview=True`" - "\nwhen constructing the AIProjectClient. Note that preview features are under development and " - "\nsubject to change. They should not be used in production environments." - ) - else: - base_url = self._config.endpoint.rstrip("/") + "/openai/v1" # pylint: disable=protected-access - - default_query = dict[str, str](kwargs.pop("default_query", None) or {}) - if agent_name is not None and "api-version" not in default_query: - default_query["api-version"] = self._config.api_version # pylint: disable=protected-access + base_url = _resolve_openai_base_url(self._config, agent_name, kwargs) + default_query = _resolve_openai_query_params(self._config, agent_name, kwargs) logger.debug( # pylint: disable=specify-parameter-names-in-call "[get_openai_client] Creating OpenAI client using Entra ID authentication, base_url = `%s`", # pylint: disable=line-too-long base_url, ) - # Allow caller to override api_key, otherwise use token provider - if "api_key" in kwargs: - api_key = kwargs.pop("api_key") - else: - api_key = get_bearer_token_provider( - self._config.credential, # pylint: disable=protected-access - "https://ai.azure.com/.default", - ) - - if "http_client" in kwargs: - http_client = kwargs.pop("http_client") - elif self._console_logging_enabled: - http_client = httpx.Client(transport=_OpenAILoggingTransport()) - else: - http_client = None - - default_headers = dict[str, str](kwargs.pop("default_headers", None) or {}) - if agent_name is not None and not _has_header_case_insensitive(default_headers, _FOUNDRY_FEATURES_HEADER_NAME): - default_headers[_FOUNDRY_FEATURES_HEADER_NAME] = _BETA_OPERATION_FEATURE_HEADERS["agents"] + api_key = self._get_openai_api_key(kwargs) + http_client = self._get_openai_http_client(kwargs) + default_headers = _resolve_openai_default_headers(agent_name, kwargs) openai_custom_user_agent = default_headers.get("User-Agent", None) @@ -195,11 +270,7 @@ def _create_openai_client(**kwargs) -> OpenAI: if openai_custom_user_agent: final_user_agent = openai_custom_user_agent else: - final_user_agent = ( - "-".join(ua for ua in [self._custom_user_agent, "AIProjectClient"] if ua) - + " " - + openai_default_user_agent - ) + final_user_agent = _build_openai_user_agent(self._custom_user_agent, openai_default_user_agent) default_headers["User-Agent"] = final_user_agent diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.pyi b/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.pyi index c40454fc9320..42009c1c227e 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.pyi +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_patch.pyi @@ -108,6 +108,11 @@ class AIProjectClient(AIProjectClientGenerated): # To make mypy happy... otherwise imports of the below result in mypy "attr-defined" error class _AuthSecretsFilter(logging.Filter): ... +def _resolve_openai_base_url(config: Any, agent_name: Optional[str], kwargs: dict) -> str: ... +def _resolve_openai_query_params(config: Any, agent_name: Optional[str], kwargs: dict) -> dict: ... +def _resolve_openai_default_headers(agent_name: Optional[str], kwargs: dict) -> dict: ... +def _build_openai_user_agent(custom_user_agent: Optional[str], openai_default_user_agent: str) -> str: ... + __all__: List[str] = ["AIProjectClient"] def patch_sdk() -> None: ... 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..74ca7f7b13ba 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 @@ -33,6 +33,17 @@ def prepare_multipart_form_data( body: Mapping[str, Any], multipart_fields: list[str], data_fields: list[str] ) -> list[FileType]: files: list[FileType] = [] + + # Append data fields first so they appear before file parts in the encoded + # multipart body. Some streaming server-side parsers (e.g. the Foundry + # hosted-agents `create_agent_version_from_code` endpoint) require small + # JSON metadata parts to precede large binary file parts; otherwise they + # report the metadata part as missing. + for data_field in data_fields: + data_entry = body.get(data_field) + if data_entry: + files.append((data_field, str(serialize_multipart_data_entry(data_entry)))) + for multipart_field in multipart_fields: multipart_entry = body.get(multipart_field) if isinstance(multipart_entry, list): @@ -40,11 +51,4 @@ def prepare_multipart_form_data( elif multipart_entry: files.append((multipart_field, multipart_entry)) - # if files is empty, sdk core library can't handle multipart/form-data correctly, so - # we put data fields into files with filename as None to avoid that scenario. - for data_field in data_fields: - data_entry = body.get(data_field) - if data_entry: - files.append((data_field, str(serialize_multipart_data_entry(data_entry)))) - return files diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_version.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_version.py index ccb75164d3bc..8abefc77cabd 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_version.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_version.py @@ -6,4 +6,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "2.1.0" +VERSION = "2.2.0" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py index 34528053a55c..6eafa71053e6 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py @@ -16,8 +16,13 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.credentials_async import AsyncTokenCredential from azure.identity.aio import get_bearer_token_provider -from .._patch import _AuthSecretsFilter -from ..models._patch import _BETA_OPERATION_FEATURE_HEADERS, _FOUNDRY_FEATURES_HEADER_NAME, _has_header_case_insensitive +from .._patch import ( + _AuthSecretsFilter, + _build_openai_user_agent, + _resolve_openai_base_url, + _resolve_openai_default_headers, + _resolve_openai_query_params, +) from ._client import AIProjectClient as AIProjectClientGenerated from .operations import TelemetryOperations @@ -101,6 +106,35 @@ def __init__( self.telemetry = TelemetryOperations(self) # type: ignore + def _get_openai_api_key(self, kwargs: dict): + """Resolve the API key for the AsyncOpenAI client. + + :param kwargs: Caller keyword arguments; ``api_key`` is popped when present. + :type kwargs: dict + :return: The API key string or a bearer-token-provider callable. + :rtype: str or Callable + """ + if "api_key" in kwargs: + return kwargs.pop("api_key") + return get_bearer_token_provider( + self._config.credential, # pylint: disable=protected-access + "https://ai.azure.com/.default", + ) + + def _get_openai_http_client(self, kwargs: dict): + """Resolve the HTTP transport client for the AsyncOpenAI client. + + :param kwargs: Caller keyword arguments; ``http_client`` is popped when present. + :type kwargs: dict + :return: An httpx.AsyncClient instance configured with logging transport, or ``None``. + :rtype: httpx.AsyncClient or None + """ + if "http_client" in kwargs: + return kwargs.pop("http_client") + if self._console_logging_enabled: + return httpx.AsyncClient(transport=_OpenAILoggingTransport()) + return None + @distributed_trace def get_openai_client(self, *, agent_name: Optional[str] = None, **kwargs: Any) -> AsyncOpenAI: """Get an authenticated AsyncOpenAI client from the `openai` package. @@ -131,51 +165,17 @@ def get_openai_client(self, *, agent_name: Optional[str] = None, **kwargs: Any) kwargs = kwargs.copy() if kwargs else {} - # Allow caller to override base_url - if "base_url" in kwargs: - base_url = kwargs.pop("base_url") - elif agent_name is not None: - if self._config.allow_preview: - base_url = ( - self._config.endpoint.rstrip("/") + f"/agents/{agent_name}/endpoint/protocols/openai" - ) # pylint: disable=protected-access - else: - raise ValueError( - "Calling `get_openai_client` method with an `agent_name` requires you to set `allow_preview=True`" - "\nwhen constructing the AIProjectClient. Note that preview features are under development and " - "\nsubject to change. They should not be used in production environments." - ) - else: - base_url = self._config.endpoint.rstrip("/") + "/openai/v1" # pylint: disable=protected-access - - default_query = dict[str, str](kwargs.pop("default_query", None) or {}) - if agent_name is not None and "api-version" not in default_query: - default_query["api-version"] = self._config.api_version # pylint: disable=protected-access + base_url = _resolve_openai_base_url(self._config, agent_name, kwargs) + default_query = _resolve_openai_query_params(self._config, agent_name, kwargs) logger.debug( # pylint: disable=specify-parameter-names-in-call "[get_openai_client] Creating OpenAI client using Entra ID authentication, base_url = `%s`", # pylint: disable=line-too-long base_url, ) - # Allow caller to override api_key, otherwise use token provider - if "api_key" in kwargs: - api_key = kwargs.pop("api_key") - else: - api_key = get_bearer_token_provider( - self._config.credential, # pylint: disable=protected-access - "https://ai.azure.com/.default", - ) - - if "http_client" in kwargs: - http_client = kwargs.pop("http_client") - elif self._console_logging_enabled: - http_client = httpx.AsyncClient(transport=_OpenAILoggingTransport()) - else: - http_client = None - - default_headers = dict[str, str](kwargs.pop("default_headers", None) or {}) - if agent_name is not None and not _has_header_case_insensitive(default_headers, _FOUNDRY_FEATURES_HEADER_NAME): - default_headers[_FOUNDRY_FEATURES_HEADER_NAME] = _BETA_OPERATION_FEATURE_HEADERS["agents"] + api_key = self._get_openai_api_key(kwargs) + http_client = self._get_openai_http_client(kwargs) + default_headers = _resolve_openai_default_headers(agent_name, kwargs) openai_custom_user_agent = default_headers.get("User-Agent", None) @@ -195,11 +195,7 @@ def _create_openai_client(**kwargs) -> AsyncOpenAI: if openai_custom_user_agent: final_user_agent = openai_custom_user_agent else: - final_user_agent = ( - "-".join(ua for ua in [self._custom_user_agent, "AIProjectClient"] if ua) - + " " - + openai_default_user_agent - ) + final_user_agent = _build_openai_user_agent(self._custom_user_agent, openai_default_user_agent) default_headers["User-Agent"] = final_user_agent 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 41e22e8fa2e8..7a9f6d37dc42 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 @@ -33,8 +33,9 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from ..._utils.model_base import Model as _Model, SdkJSONEncoder, _deserialize, _failsafe_deserialize from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import prepare_multipart_form_data from ...operations._operations import ( build_agents_create_version_from_manifest_request, build_agents_create_version_request, @@ -44,41 +45,85 @@ build_agents_get_version_request, build_agents_list_request, build_agents_list_versions_request, + build_beta_agents_cancel_optimization_job_request, + build_beta_agents_create_optimization_job_request, build_beta_agents_create_session_request, + build_beta_agents_create_version_from_code_request, + build_beta_agents_delete_optimization_job_request, build_beta_agents_delete_session_file_request, build_beta_agents_delete_session_request, + build_beta_agents_download_code_request, build_beta_agents_download_session_file_request, + build_beta_agents_get_optimization_candidate_config_request, + build_beta_agents_get_optimization_candidate_request, + build_beta_agents_get_optimization_candidate_results_request, + build_beta_agents_get_optimization_job_request, build_beta_agents_get_session_files_request, build_beta_agents_get_session_log_stream_request, build_beta_agents_get_session_request, + build_beta_agents_list_optimization_candidates_request, + build_beta_agents_list_optimization_jobs_request, 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, build_beta_evaluators_update_version_request, build_beta_insights_generate_request, build_beta_insights_get_request, build_beta_insights_list_request, + build_beta_memory_stores_create_memory_request, build_beta_memory_stores_create_request, + build_beta_memory_stores_delete_memory_request, build_beta_memory_stores_delete_request, build_beta_memory_stores_delete_scope_request, + build_beta_memory_stores_get_memory_request, build_beta_memory_stores_get_request, + build_beta_memory_stores_list_memories_request, build_beta_memory_stores_list_request, build_beta_memory_stores_search_memories_request, build_beta_memory_stores_update_memories_request, + build_beta_memory_stores_update_memory_request, build_beta_memory_stores_update_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_create_version_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, + build_beta_routines_create_or_update_request, + build_beta_routines_delete_request, + build_beta_routines_disable_request, + build_beta_routines_dispatch_request, + build_beta_routines_enable_request, + build_beta_routines_get_request, + build_beta_routines_list_request, + build_beta_routines_list_runs_request, build_beta_schedules_create_or_update_request, build_beta_schedules_delete_request, build_beta_schedules_get_request, @@ -155,10 +200,13 @@ 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.routines = BetaRoutinesOperations(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) self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) + self.datasets = BetaDatasetsOperations(self._client, self._config, self._serialize, self._deserialize) class AgentsOperations: @@ -244,11 +292,19 @@ async def get(self, agent_name: str, **kwargs: Any) -> _models.AgentDetails: return deserialized # type: ignore @distributed_trace_async - async def delete(self, agent_name: str, **kwargs: Any) -> _models.DeleteAgentResponse: - """Deletes an agent. + async def delete( + self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any + ) -> _models.DeleteAgentResponse: + """Deletes an agent. For hosted agents, if any version has active sessions, the request is + rejected with HTTP 409 unless ``force`` is set to true. When force is true, all associated + sessions are cascade-deleted along with the agent and its versions. :param agent_name: The name of the agent to delete. Required. :type agent_name: str + :keyword force: For Hosted Agents, if true, force-deletes the agent even if its versions have + active sessions, cascading deletion to all associated sessions. Defaults to ``false``. This + value is not relevant for other Agent types. Default value is None. + :paramtype force: bool :return: DeleteAgentResponse. The DeleteAgentResponse is compatible with MutableMapping :rtype: ~azure.ai.projects.models.DeleteAgentResponse :raises ~azure.core.exceptions.HttpResponseError: @@ -268,6 +324,7 @@ async def delete(self, agent_name: str, **kwargs: Any) -> _models.DeleteAgentRes _request = build_agents_delete_request( agent_name=agent_name, + force=force, api_version=self._config.api_version, headers=_headers, params=_params, @@ -321,7 +378,7 @@ def list( """Returns the list of all agents. :keyword kind: Filter agents by kind. If not provided, all agents are returned. Known values - are: "prompt", "hosted", and "workflow". Default value is None. + are: "prompt", "hosted", "workflow", and "external". Default value is None. :paramtype kind: str or ~azure.ai.projects.models.AgentKind :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the @@ -885,14 +942,20 @@ async def get_version(self, agent_name: str, agent_version: str, **kwargs: Any) @distributed_trace_async async def delete_version( - self, agent_name: str, agent_version: str, **kwargs: Any + self, agent_name: str, agent_version: str, *, force: Optional[bool] = None, **kwargs: Any ) -> _models.DeleteAgentVersionResponse: - """Deletes a specific version of an agent. + """Deletes a specific version of an agent. For hosted agents, if the version has active sessions, + the request is rejected with HTTP 409 unless ``force`` is set to true. When force is true, all + sessions associated with this version are cascade-deleted. :param agent_name: The name of the agent to delete. Required. :type agent_name: str :param agent_version: The version of the agent to delete. Required. :type agent_version: str + :keyword force: For Hosted Agents, if true, force-deletes the version even if it has active + sessions, cascading deletion to all associated sessions. Defaults to ``false``. This value is + not relevant for other Agent types. Default value is None. + :paramtype force: bool :return: DeleteAgentVersionResponse. The DeleteAgentVersionResponse is compatible with MutableMapping :rtype: ~azure.ai.projects.models.DeleteAgentVersionResponse @@ -914,6 +977,7 @@ async def delete_version( _request = build_agents_delete_version_request( agent_name=agent_name, agent_version=agent_version, + force=force, api_version=self._config.api_version, headers=_headers, params=_params, @@ -2995,7 +3059,7 @@ async def create_or_update( return deserialized # type: ignore -class BetaAgentsOperations: +class BetaAgentsOperations: # pylint: disable=too-many-public-methods """ .. warning:: **DO NOT** instantiate this class directly. @@ -3018,7 +3082,7 @@ async def patch_agent_details( agent_name: str, *, content_type: str = "application/merge-patch+json", - agent_endpoint: Optional[_models.AgentEndpoint] = None, + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, agent_card: Optional[_models.AgentCard] = None, **kwargs: Any ) -> _models.AgentDetails: @@ -3030,7 +3094,7 @@ async def patch_agent_details( 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.AgentEndpoint + :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 @@ -3080,7 +3144,7 @@ async def patch_agent_details( agent_name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - agent_endpoint: Optional[_models.AgentEndpoint] = None, + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, agent_card: Optional[_models.AgentCard] = None, **kwargs: Any ) -> _models.AgentDetails: @@ -3091,7 +3155,7 @@ async def patch_agent_details( :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.AgentEndpoint + :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 @@ -3166,13 +3230,232 @@ async def patch_agent_details( return deserialized # type: ignore + @overload + async def create_version_from_code( + self, + agent_name: str, + content: _models.CreateAgentVersionFromCodeContent, + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_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_version_from_code( + self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_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 create_version_from_code( + self, + agent_name: str, + content: Union[_models.CreateAgentVersionFromCodeContent, JSON], + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_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: 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 = { + 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.AgentVersionDetails] = 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) + + _request = build_beta_agents_create_version_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, + ) + 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.AgentVersionDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def download_code( + self, agent_name: str, *, agent_version: Optional[str] = None, **kwargs: Any + ) -> AsyncIterator[bytes]: + """Download the code zip for a code-based hosted agent. + Returns the previously-uploaded zip (``application/zip``). + + If ``agent_version`` is supplied, returns that version's code zip; otherwise + returns the latest version's code zip. + + The SHA-256 digest of the returned bytes matches the ``content_hash`` on the + resolved version's ``code_configuration``. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :keyword agent_version: The version of the agent whose code zip should be downloaded. + If omitted, the latest version's code zip is returned. Default value is None. + :paramtype agent_version: str + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] + :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[AsyncIterator[bytes]] = kwargs.pop("cls", None) + + _request = build_beta_agents_download_code_request( + agent_name=agent_name, + agent_version=agent_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", 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]: + 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["x-ms-agent-version"] = self._deserialize("str", response.headers.get("x-ms-agent-version")) + 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 + @overload async def create_session( self, agent_name: str, *, - isolation_key: str, version_indicator: _models.VersionIndicator, + user_isolation_key: Optional[str] = None, content_type: str = "application/json", agent_session_id: Optional[str] = None, **kwargs: Any @@ -3183,11 +3466,11 @@ async def create_session( :param agent_name: The name of the agent to create a session for. Required. :type agent_name: str - :keyword isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str :keyword version_indicator: Determines which agent version backs the session. Required. :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str @@ -3201,7 +3484,13 @@ async def create_session( @overload async def create_session( - self, agent_name: str, body: JSON, *, isolation_key: str, content_type: str = "application/json", **kwargs: Any + self, + agent_name: str, + body: JSON, + *, + user_isolation_key: Optional[str] = None, + 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 @@ -3211,9 +3500,9 @@ async def create_session( :type agent_name: str :param body: Required. :type body: JSON - :keyword isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str @@ -3228,7 +3517,7 @@ async def create_session( agent_name: str, body: IO[bytes], *, - isolation_key: str, + user_isolation_key: Optional[str] = None, content_type: str = "application/json", **kwargs: Any ) -> _models.AgentSessionResource: @@ -3240,9 +3529,9 @@ async def create_session( :type agent_name: str :param body: Required. :type body: IO[bytes] - :keyword isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str @@ -3257,8 +3546,8 @@ async def create_session( agent_name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - isolation_key: str, version_indicator: _models.VersionIndicator = _Unset, + user_isolation_key: Optional[str] = None, agent_session_id: Optional[str] = None, **kwargs: Any ) -> _models.AgentSessionResource: @@ -3270,11 +3559,11 @@ async def create_session( :type agent_name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str :keyword version_indicator: Determines which agent version backs the session. Required. :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: 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 @@ -3310,7 +3599,7 @@ async def create_session( _request = build_beta_agents_create_session_request( agent_name=agent_name, - isolation_key=isolation_key, + user_isolation_key=user_isolation_key, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -3354,13 +3643,18 @@ async def create_session( return deserialized # type: ignore @distributed_trace_async - async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _models.AgentSessionResource: + async def get_session( + self, agent_name: str, session_id: str, *, user_isolation_key: Optional[str] = None, **kwargs: Any + ) -> _models.AgentSessionResource: """Retrieves a session by ID. :param agent_name: The name of the agent. Required. :type agent_name: str :param session_id: The session identifier. Required. :type session_id: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping :rtype: ~azure.ai.projects.models.AgentSessionResource :raises ~azure.core.exceptions.HttpResponseError: @@ -3381,6 +3675,7 @@ async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _request = build_beta_agents_get_session_request( agent_name=agent_name, session_id=session_id, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3422,7 +3717,9 @@ 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, *, isolation_key: str, **kwargs: Any) -> None: + async def delete_session( + self, agent_name: str, session_id: str, *, user_isolation_key: Optional[str] = None, **kwargs: Any + ) -> None: """Deletes a session synchronously. Returns 204 No Content when the session is deleted or does not exist. @@ -3430,9 +3727,9 @@ async def delete_session(self, agent_name: str, session_id: str, *, isolation_ke :type agent_name: str :param session_id: The session identifier. Required. :type session_id: str - :keyword isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -3453,7 +3750,7 @@ async def delete_session(self, agent_name: str, session_id: str, *, isolation_ke _request = build_beta_agents_delete_session_request( agent_name=agent_name, session_id=session_id, - isolation_key=isolation_key, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3486,6 +3783,7 @@ def list_sessions( self, agent_name: str, *, + user_isolation_key: Optional[str] = None, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, @@ -3495,6 +3793,9 @@ def list_sessions( :param agent_name: The name of the agent. Required. :type agent_name: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: 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. @@ -3530,6 +3831,7 @@ def prepare_request(_continuation_token=None): _request = build_beta_agents_list_sessions_request( agent_name=agent_name, + user_isolation_key=user_isolation_key, limit=limit, order=order, after=_continuation_token, @@ -3678,8 +3980,15 @@ async def get_session_log_stream( @distributed_trace_async async def _upload_session_file( - self, agent_name: str, agent_session_id: str, content: bytes, *, path: str, **kwargs: Any - ) -> _models.SessionFileWriteResponse: + self, + agent_name: str, + agent_session_id: str, + content: bytes, + *, + path: str, + user_isolation_key: Optional[str] = None, + **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. @@ -3692,9 +4001,11 @@ async def _upload_session_file( :keyword path: The destination file path within the sandbox, relative to the session home directory. Required. :paramtype path: str - :return: SessionFileWriteResponse. The SessionFileWriteResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.SessionFileWriteResponse + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SessionFileWriteResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3709,7 +4020,7 @@ async def _upload_session_file( _params = kwargs.pop("params", {}) or {} content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) - cls: ClsType[_models.SessionFileWriteResponse] = kwargs.pop("cls", None) + cls: ClsType[_models.SessionFileWriteResult] = kwargs.pop("cls", None) _content = content @@ -3717,6 +4028,7 @@ async def _upload_session_file( agent_name=agent_name, agent_session_id=agent_session_id, path=path, + user_isolation_key=user_isolation_key, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -3752,7 +4064,7 @@ async def _upload_session_file( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SessionFileWriteResponse, response.json()) + deserialized = _deserialize(_models.SessionFileWriteResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3761,7 +4073,13 @@ async def _upload_session_file( @distributed_trace_async async def download_session_file( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + self, + agent_name: str, + agent_session_id: str, + *, + path: str, + user_isolation_key: Optional[str] = None, + **kwargs: Any ) -> AsyncIterator[bytes]: """Download a file from the session sandbox as a binary stream. @@ -3772,6 +4090,9 @@ async def download_session_file( :keyword path: The file path to download from the sandbox, relative to the session home directory. Required. :paramtype path: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :return: AsyncIterator[bytes] :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: @@ -3793,6 +4114,7 @@ async def download_session_file( agent_name=agent_name, agent_session_id=agent_session_id, path=path, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3832,8 +4154,14 @@ async def download_session_file( @distributed_trace_async async def get_session_files( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any - ) -> _models.SessionDirectoryListResponse: + self, + agent_name: str, + agent_session_id: str, + *, + path: str, + user_isolation_key: Optional[str] = None, + **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). @@ -3843,9 +4171,12 @@ async def get_session_files( :type agent_session_id: str :keyword path: The directory path to list, relative to the session home directory. Required. :paramtype path: str - :return: SessionDirectoryListResponse. The SessionDirectoryListResponse is compatible with + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :return: SessionDirectoryListResult. The SessionDirectoryListResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionDirectoryListResponse + :rtype: ~azure.ai.projects.models.SessionDirectoryListResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3859,12 +4190,13 @@ async def get_session_files( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SessionDirectoryListResponse] = kwargs.pop("cls", None) + cls: ClsType[_models.SessionDirectoryListResult] = kwargs.pop("cls", None) _request = build_beta_agents_get_session_files_request( agent_name=agent_name, agent_session_id=agent_session_id, path=path, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3898,7 +4230,7 @@ async def get_session_files( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SessionDirectoryListResponse, response.json()) + deserialized = _deserialize(_models.SessionDirectoryListResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3907,7 +4239,14 @@ async def get_session_files( @distributed_trace_async async def delete_session_file( - self, agent_name: str, agent_session_id: str, *, path: str, recursive: Optional[bool] = None, **kwargs: Any + self, + agent_name: str, + agent_session_id: str, + *, + path: str, + recursive: Optional[bool] = None, + user_isolation_key: Optional[str] = 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. @@ -3922,6 +4261,9 @@ async def delete_session_file( :keyword recursive: Whether to recursively delete directory contents. Defaults to false. Default value is None. :paramtype recursive: bool + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -3944,6 +4286,7 @@ async def delete_session_file( agent_session_id=agent_session_id, path=path, recursive=recursive, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3971,32 +4314,99 @@ async def delete_session_file( if cls: return cls(pipeline_response, None, {}) # type: ignore + @overload + async def create_optimization_job( + self, + job: _models.OptimizationJob, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. -class BetaEvaluationTaxonomiesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`evaluation_taxonomies` attribute. - """ + :param job: The job to create. Required. + :type job: ~azure.ai.projects.models.OptimizationJob + :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: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob + :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_optimization_job( + self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. + + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :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: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_optimization_job( + self, + job: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. + + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :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: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: - """Get an evaluation run by name. + async def create_optimization_job( + self, job: Union[_models.OptimizationJob, JSON, IO[bytes]], *, operation_id: Optional[str] = None, **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. - :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 + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :param job: The job to create. Is one of the following types: OptimizationJob, JSON, IO[bytes] + Required. + :type job: ~azure.ai.projects.models.OptimizationJob 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: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4007,13 +4417,94 @@ async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: } 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.EvaluationTaxonomy] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.OptimizationJob] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_get_request( - name=name, + 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_agents_create_optimization_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.OptimizationJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def get_optimization_job(self, job_id: str, **kwargs: Any) -> _models.OptimizationJob: + """Get info about an agent optimization job. + + Get an optimization job by id. Emits ``Retry-After`` while the job is non-terminal. + + :param job_id: The ID of the job. Required. + :type job_id: str + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob + :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.OptimizationJob] = kwargs.pop("cls", None) + + _request = build_beta_agents_get_optimization_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4038,36 +4529,68 @@ 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["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.EvaluationTaxonomy, response.json()) + deserialized = _deserialize(_models.OptimizationJob, 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( - self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.EvaluationTaxonomy"]: - """List evaluation taxonomies. + def list_optimization_jobs( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.JobStatus]] = None, + agent_name: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.OptimizationJob"]: + """Returns a list of agent optimization jobs. - :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] + List optimization jobs. Supports cursor pagination and optional ``status`` / ``agent_name`` + filters. + + :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 status: Filter to jobs in this lifecycle state. Known values are: "queued", + "in_progress", "succeeded", "failed", and "cancelled". Default value is None. + :paramtype status: str or ~azure.ai.projects.models.JobStatus + :keyword agent_name: Filter to jobs targeting this agent name. Default value is None. + :paramtype agent_name: str + :return: An iterator like instance of OptimizationJob + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.OptimizationJob] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.EvaluationTaxonomy]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.OptimizationJob]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -4077,60 +4600,37 @@ def list( } 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) + def prepare_request(_continuation_token=None): + _request = build_beta_agents_list_optimization_jobs_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + status=status, + 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) return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.EvaluationTaxonomy], - deserialized.get("value", []), + List[_models.OptimizationJob], + deserialized.get("data", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + return deserialized.get("last_id") or None, AsyncList(list_of_elem) - async def get_next(next_link=None): - _request = prepare_request(next_link) + 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 @@ -4140,20 +4640,26 @@ async 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 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 cancel_optimization_job(self, job_id: str, **kwargs: Any) -> _models.OptimizationJob: + """Cancels an agent optimization job. - :param name: The name of the resource. Required. - :type name: str - :return: None - :rtype: None + Request cancellation. Idempotent on terminal states. + + :param job_id: The ID of the job to cancel. Required. + :type job_id: str + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4167,10 +4673,10 @@ 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.OptimizationJob] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_delete_request( - name=name, + _request = build_beta_agents_cancel_optimization_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4180,87 +4686,131 @@ 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) - 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.OptimizationJob, response.json()) if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore - @overload - async def create( - self, name: str, body: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + return deserialized # type: ignore - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. Required. - :type body: ~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: - """ + @distributed_trace_async + async def delete_optimization_job(self, job_id: str, **kwargs: Any) -> None: + """Deletes an agent optimization job. - @overload - async def create( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + Delete the job and its candidate artifacts. Cancels first if non-terminal. - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + :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 {}) - @overload - async def create( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create 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 body: The evaluation taxonomy. 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: 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) + + _request = build_beta_agents_delete_optimization_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 @distributed_trace_async - async def create( - self, name: str, body: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + async def list_optimization_candidates( + self, + job_id: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentsPagedResultOptimizationCandidate: + """Returns a list of candidates for an optimization job. - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, JSON, - IO[bytes] Required. - :type body: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + List candidates produced by a job. + + :param job_id: The optimization job id. Required. + :type job_id: 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 after: A cursor for use in pagination. ``after`` 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 after=obj_foo in order to fetch the next page of the list. Default + value is None. + :paramtype after: str + :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: AgentsPagedResultOptimizationCandidate. The AgentsPagedResultOptimizationCandidate is + compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentsPagedResultOptimizationCandidate :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4271,24 +4821,18 @@ 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(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.AgentsPagedResultOptimizationCandidate] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_create_request( - name=name, - content_type=content_type, + _request = build_beta_agents_list_optimization_candidates_request( + job_id=job_id, + limit=limit, + order=order, + after=after, + before=before, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -4305,92 +4849,116 @@ async 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: 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 = _deserialize(_models.AgentsPagedResultOptimizationCandidate, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - async def update( - self, name: str, body: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + @distributed_trace_async + async def get_optimization_candidate( + self, job_id: str, candidate_id: str, **kwargs: Any + ) -> _models.OptimizationCandidate: + """Get a candidate by id. - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. Required. - :type body: ~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 + Get a single candidate manifest and aggregated evaluation summary. + + :param job_id: The optimization job id. Required. + :type job_id: str + :param candidate_id: The candidate id. Required. + :type candidate_id: str + :return: OptimizationCandidate. The OptimizationCandidate is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationCandidate :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.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 body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + cls: ClsType[_models.OptimizationCandidate] = kwargs.pop("cls", None) - @overload - async def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + _request = build_beta_agents_get_optimization_candidate_request( + job_id=job_id, + candidate_id=candidate_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) - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + _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.OptimizationCandidate, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace_async - async def update( - self, name: str, body: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + async def get_optimization_candidate_config( + self, job_id: str, candidate_id: str, **kwargs: Any + ) -> _models.CandidateDeployConfig: + """Get candidate deploy config. - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, JSON, - IO[bytes] Required. - :type body: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + Get the candidate's deploy config JSON. Used to compose ``agents.create_version(...)`` from a + candidate. + + :param job_id: The optimization job id. Required. + :type job_id: str + :param candidate_id: The candidate id. Required. + :type candidate_id: str + :return: CandidateDeployConfig. The CandidateDeployConfig is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CandidateDeployConfig :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4401,24 +4969,15 @@ 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(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.CandidateDeployConfig] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_update_request( - name=name, - content_type=content_type, + _request = build_beta_agents_get_optimization_candidate_config_request( + job_id=job_id, + candidate_id=candidate_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -4442,65 +5001,38 @@ 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.CandidateDeployConfig, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace_async + async def get_optimization_candidate_results( + self, job_id: str, candidate_id: str, **kwargs: Any + ) -> _models.CandidateResults: + """Get candidate evaluation results. -class BetaEvaluatorsOperations: - """ - .. 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. - """ - - 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, - *, - 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. + Get full per-task evaluation results for a candidate. - :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] + :param job_id: The optimization job id. Required. + :type job_id: str + :param candidate_id: The candidate id. Required. + :type candidate_id: str + :return: CandidateResults. The CandidateResults is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CandidateResults :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, @@ -4509,101 +5041,151 @@ def list_versions( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _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) + cls: ClsType[_models.CandidateResults] = 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) + _request = build_beta_agents_get_optimization_candidate_results_request( + job_id=job_id, + candidate_id=candidate_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) - return _request + _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 extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.EvaluatorVersion], - deserialized.get("value", []), + 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, ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + raise HttpResponseError(response=response, model=error) - 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.CandidateResults, 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) +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:`evaluation_taxonomies` 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.EvaluationTaxonomy: + """Get an evaluation run by name. + + :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 + :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.EvaluationTaxonomy] = kwargs.pop("cls", None) + + _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) + + _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.EvaluationTaxonomy, response.json()) + + 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, @@ -4616,9 +5198,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, @@ -4658,7 +5240,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: @@ -4683,16 +5265,13 @@ 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. + 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 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 + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4706,11 +5285,10 @@ async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.E _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_evaluators_get_version_request( + _request = build_beta_evaluation_taxonomies_delete_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4720,157 +5298,87 @@ async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.E } _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) 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 + return cls(pipeline_response, None, {}) # 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. + @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 resource. Required. + :param name: The name of the evaluation taxonomy. 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: - """ - 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_evaluators_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 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 name: The name of the resource. 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 = { @@ -4885,16 +5393,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, @@ -4915,7 +5423,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 @@ -4927,7 +5435,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 @@ -4935,96 +5443,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 = { @@ -5039,18 +5523,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, @@ -5082,7 +5565,7 @@ 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 @@ -5090,14 +5573,14 @@ async def update_version( return deserialized # type: ignore -class BetaInsightsOperations: +class BetaEvaluatorsOperations: """ .. 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. + :attr:`evaluators` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -5107,68 +5590,35 @@ 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 generate( - self, insight: _models.Insight, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Insight: - """Generate Insights. + @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. - :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 - :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 + :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 {} - @overload - async def generate( - self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Insight: - """Generate Insights. + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) - :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: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def generate( - self, insight: IO[bytes], *, 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: 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 - :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. - - :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 = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -5177,166 +5627,101 @@ async def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwa } 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.Insight] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(insight, (IOBase, bytes)): - _content = insight - else: - _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + def prepare_request(next_link=None): + if not next_link: - _request = build_beta_insights_generate_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) + _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 _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.Insight, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @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 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 {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.Insight] = kwargs.pop("cls", None) - - _request = build_beta_insights_get_request( - insight_id=insight_id, - 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) - - _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 - ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - 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 = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.Insight, 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, {}) # type: ignore + return pipeline_response - return deserialized # type: ignore + return AsyncItemPaged(get_next, extract_data) @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, + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, + limit: Optional[int] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.Insight"]: - """List all insights in reverse chronological order (newest first). + ) -> AsyncItemPaged["_models.EvaluatorVersion"]: + """List the latest version of each evaluator. - :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] + :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 {} - cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -5349,12 +5734,9 @@ def list( def prepare_request(next_link=None): if not next_link: - _request = build_beta_insights_list_request( + _request = build_beta_evaluators_list_request( type=type, - eval_id=eval_id, - run_id=run_id, - agent_name=agent_name, - include_coordinates=include_coordinates, + limit=limit, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5394,7 +5776,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.Insight], + List[_models.EvaluatorVersion], deserialized.get("value", []), ) if cls: @@ -5412,122 +5794,201 @@ async 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) - 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 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. -class BetaMemoryStoresOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + :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 {}) - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`memory_stores` 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[_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. + + :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: + """ + 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_evaluators_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 create( + async def create_version( self, - *, name: str, - definition: _models.MemoryStoreDefinition, + evaluator_version: _models.EvaluatorVersion, + *, content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :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 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 - :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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :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 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 body: Required. - :type body: 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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :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 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 body: Required. - :type body: 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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :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 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 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 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 = { @@ -5542,23 +6003,17 @@ 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.EvaluatorVersion] = 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(evaluator_version, (IOBase, bytes)): + _content = evaluator_version else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_create_request( + _request = build_beta_evaluators_create_version_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -5578,23 +6033,19 @@ 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 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.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -5602,91 +6053,96 @@ async def create( return deserialized # type: ignore @overload - async def update( + async def update_version( self, name: str, + version: str, + evaluator_version: _models.EvaluatorVersion, *, content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. - :param name: The name of the memory store to update. Required. + :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 - :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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + 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 memory store to update. Required. + :param name: The name of the resource. Required. :type name: str - :param body: Required. - :type body: JSON + :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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :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. + 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 memory store to update. Required. + :param name: The name of the resource. Required. :type name: str - :param body: Required. - :type body: IO[bytes] + :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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def update( + async def update_version( self, name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, + version: str, + evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. - :param name: The name of the memory store to update. Required. + :param name: The name of the resource. 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 + :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 = { @@ -5701,20 +6157,18 @@ async def update( _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.EvaluatorVersion] = 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 + if isinstance(evaluator_version, (IOBase, bytes)): + _content = evaluator_version else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_update_request( + _request = build_beta_evaluators_update_version_request( name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -5741,30 +6195,116 @@ async def update( 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.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + async def pending_upload( + self, + name: str, + version: str, + pending_upload_request: _models.PendingUploadRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: ~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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def pending_upload( + self, + name: str, + version: str, + pending_upload_request: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def pending_upload( + self, + name: str, + version: str, + pending_upload_request: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: 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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: - """Retrieve a memory store. + async def pending_upload( + self, + name: str, + version: str, + pending_upload_request: Union[_models.PendingUploadRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. - :param name: The name of the memory store to retrieve. Required. + :param name: Required. :type name: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Is one of the following + types: PendingUploadRequest, JSON, IO[bytes] Required. + :type pending_upload_request: ~azure.ai.projects.models.PendingUploadRequest or JSON or + IO[bytes] + :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5775,14 +6315,25 @@ async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: } 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.MemoryStoreDetails] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.PendingUploadResponse] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_get_request( + content_type = content_type or "application/json" + _content = None + if isinstance(pending_upload_request, (IOBase, bytes)): + _content = pending_upload_request + else: + _content = json.dumps(pending_upload_request, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_evaluators_pending_upload_request( name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -5815,111 +6366,111 @@ 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.PendingUploadResponse, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( + @overload + async def get_credentials( self, + name: str, + version: str, + credential_request: _models.EvaluatorCredentialRequest, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + content_type: str = "application/json", **kwargs: Any - ) -> AsyncItemPaged["_models.MemoryStoreDetails"]: - """List all memory stores. + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. - :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] + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Required. + :type credential_request: ~azure.ai.projects.models.EvaluatorCredentialRequest + :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: """ - _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 + @overload + async def get_credentials( + self, + name: str, + version: str, + credential_request: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. - 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) + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Required. + :type credential_request: 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: + """ - return pipeline_response + @overload + async def get_credentials( + self, + name: str, + version: str, + credential_request: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. - return AsyncItemPaged(get_next, extract_data) + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Required. + :type credential_request: 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 delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: - """Delete a memory store. + async def get_credentials( + self, + name: str, + version: str, + credential_request: Union[_models.EvaluatorCredentialRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. - :param name: The name of the memory store to delete. Required. + :param name: Required. :type name: str - :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Is one of the following types: + EvaluatorCredentialRequest, JSON, IO[bytes] Required. + :type credential_request: ~azure.ai.projects.models.EvaluatorCredentialRequest 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 = { @@ -5930,14 +6481,25 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreRes } 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.DeleteMemoryStoreResult] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_delete_request( + content_type = content_type or "application/json" + _content = None + if isinstance(credential_request, (IOBase, bytes)): + _content = credential_request + else: + _content = json.dumps(credential_request, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_evaluators_get_credentials_request( name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -5970,7 +6532,7 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreRes if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteMemoryStoreResult, response.json()) + deserialized = _deserialize(_models.DatasetCredential, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -5978,56 +6540,102 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreRes return deserialized # type: ignore @overload - async def _search_memories( + async def create_generation_job( self, - name: str, + job: _models.EvaluatorGenerationJob, *, - scope: str, + operation_id: Optional[str] = None, 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: ... + ) -> _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: ~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: + """ + @overload - async def _search_memories( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... + 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: + """ + @overload - async def _search_memories( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... + async def create_generation_job( + self, + job: IO[bytes], + *, + 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: 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 + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace_async - async def _search_memories( + async def create_generation_job( self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, + job: Union[_models.EvaluatorGenerationJob, JSON, IO[bytes]], *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_search_id: Optional[str] = None, - options: Optional[_models.MemorySearchOptions] = None, + operation_id: Optional[str] = None, **kwargs: Any - ) -> _models.MemoryStoreSearchResult: - """Search for relevant memories from a memory store based on conversation context. + ) -> _models.EvaluatorGenerationJob: + """Creates an evaluator generation job. - :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 + Creates an evaluator generation job. The service generates rubric-based evaluator definitions + from the provided source materials asynchronously. + + :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 = { @@ -6042,27 +6650,17 @@ async def _search_memories( _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) + cls: ClsType[_models.EvaluatorGenerationJob] = 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 + 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_memory_stores_search_memories_request( - name=name, + _request = build_beta_evaluators_create_generation_job_request( + operation_id=operation_id, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -6082,7 +6680,7 @@ async def _search_memories( 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 @@ -6095,27 +6693,32 @@ async def _search_memories( ) 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.MemoryStoreSearchResult, response.json()) + deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # 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]: + @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, @@ -6124,34 +6727,14 @@ async def _update_memories_initial( } 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[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 + cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_update_memories_request( - name=name, - content_type=content_type, + _request = build_beta_evaluators_get_generation_job_request( + job_id=job_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -6161,18 +6744,19 @@ async def _update_memories_initial( _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 ) 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 + 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, @@ -6181,209 +6765,121 @@ async def _update_memories_initial( raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + 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.EvaluatorGenerationJob, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @overload - async def _begin_update_memories( + @distributed_trace + def list_generation_jobs( 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, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = 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]: ... + ) -> AsyncItemPaged["_models.EvaluatorGenerationJob"]: + """Returns a list of evaluator generation jobs. - @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. + Returns a list of evaluator generation jobs. - :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 + :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 EvaluatorGenerationJob :rtype: - ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.MemoryStoreUpdateCompletedResult] + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluatorGenerationJob] :raises ~azure.core.exceptions.HttpResponseError: """ - _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.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, + cls: ClsType[List[_models.EvaluatorGenerationJob]] = 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_evaluators_list_generation_jobs_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, headers=_headers, params=_params, - **kwargs ) - await raw_result.http_response.read() # type: ignore - kwargs.pop("error_map", None) + 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 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") + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluatorGenerationJob], + deserialized.get("data", []), ) - - deserialized = _deserialize(_models.MemoryStoreUpdateCompletedResult, response.json().get("result", {})) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - return deserialized + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - 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, + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - return AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]( - self._client, raw_result, get_long_running_output, polling_method # type: ignore - ) - - @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. - - :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 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 - :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. + response = pipeline_response.http_response - :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 - :raises ~azure.core.exceptions.HttpResponseError: - """ + 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) - @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. + return pipeline_response - :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 - :raises ~azure.core.exceptions.HttpResponseError: - """ + return AsyncItemPaged(get_next, extract_data) @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 cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: + """Cancels an evaluator generation job. - :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 + Cancels an evaluator generation job by its ID. + + :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 :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6394,29 +6890,14 @@ async def delete_scope( } 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.MemoryStoreDeleteScopeResult] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluatorGenerationJob] = 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)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_delete_scope_request( - name=name, - content_type=content_type, + _request = build_beta_evaluators_cancel_generation_job_request( + job_id=job_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -6449,39 +6930,22 @@ 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.EvaluatorGenerationJob, 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. + 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. - :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 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 = { @@ -6495,10 +6959,10 @@ async 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[None] = kwargs.pop("cls", None) - _request = build_beta_red_teams_get_request( - name=name, + _request = build_beta_evaluators_delete_generation_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -6508,176 +6972,102 @@ async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: } _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) - 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, - 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.RedTeam], - deserialized.get("value", []), + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + raise HttpResponseError(response=response, model=error) - async def get_next(next_link=None): - _request = prepare_request(next_link) + if cls: + 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) - raise HttpResponseError(response=response) +class BetaInsightsOperations: + """ + .. 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:`insights` 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 create( - self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. + async def generate( + self, insight: _models.Insight, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - :param red_team: Redteam to be run. Required. - :type red_team: ~azure.ai.projects.models.RedTeam + :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 - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :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. + async def generate( + self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - :param red_team: Redteam to be run. Required. - :type red_team: 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: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :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. + async def generate( + self, insight: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - :param red_team: Redteam to be run. Required. - :type red_team: 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: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :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, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + async def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: + """Generate Insights. - :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 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 = { @@ -6692,16 +7082,16 @@ async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwar _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.Insight] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(red_team, (IOBase, bytes)): - _content = red_team + if isinstance(insight, (IOBase, bytes)): + _content = insight else: - _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_red_teams_create_request( + _request = build_beta_insights_generate_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -6737,87 +7127,26 @@ async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwar if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RedTeam, response.json()) + deserialized = _deserialize(_models.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @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. -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 + :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 = { @@ -6831,10 +7160,11 @@ async 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.Insight] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_request( - schedule_id=schedule_id, + _request = build_beta_insights_get_request( + insight_id=insight_id, + include_coordinates=include_coordinates, api_version=self._config.api_version, headers=_headers, params=_params, @@ -6859,12 +7189,16 @@ async 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.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6875,25 +7209,35 @@ async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: def list( self, *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = 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.Schedule"]: - """List all schedules. + ) -> AsyncItemPaged["_models.Insight"]: + """List all insights in reverse chronological order (newest first). - :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] + :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.Schedule]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -6906,9 +7250,12 @@ def list( def prepare_request(next_link=None): if not next_link: - _request = build_beta_schedules_list_request( + _request = build_beta_insights_list_request( type=type, - enabled=enabled, + 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, @@ -6948,7 +7295,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.Schedule], + List[_models.Insight], deserialized.get("value", []), ) if cls: @@ -6966,104 +7313,153 @@ async 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 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") + @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 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 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 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: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :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 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 create( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: JSON + :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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :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 create( + self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: IO[bytes] + :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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :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, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + 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 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 + :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) + cls: ClsType[_models.MemoryStoreDetails] = 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(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_memory_stores_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7083,35 +7479,115 @@ 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 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.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. + + :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 + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update( + self, name: str, body: JSON, *, 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: 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 get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: - """Get a schedule run by id. + 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 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 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 = { @@ -7122,15 +7598,27 @@ async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models } 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.ScheduleRun] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_run_request( - schedule_id=schedule_id, - run_id=run_id, + 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, ) @@ -7163,40 +7651,23 @@ async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ScheduleRun, 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_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_async + async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: + """Retrieve a memory store. - :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] + :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: """ - _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, @@ -7205,61 +7676,124 @@ def list_runs( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _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) + 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) + _request = build_beta_memory_stores_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) - return _request + _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 extract_data(pipeline_response): + 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 + 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.ScheduleRun], - deserialized.get("value", []), + List[_models.MemoryStoreDetails], + deserialized.get("data", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + return deserialized.get("last_id") or None, AsyncList(list_of_elem) - async def get_next(next_link=None): - _request = prepare_request(next_link) + 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 @@ -7269,132 +7803,24 @@ async 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 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. - - :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 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 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 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: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject - :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. - - :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: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject - :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 delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: + """Delete a memory store. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. + :param name: The name of the memory store to delete. 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 + :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7405,29 +7831,14 @@ async def create_version( } 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.ToolboxVersionObject] = 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 - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.DeleteMemoryStoreResult] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_create_version_request( + _request = build_beta_memory_stores_delete_request( name=name, - content_type=content_type, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -7460,23 +7871,66 @@ 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.DeleteMemoryStoreResult, 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.ToolboxObject: - """Retrieve a toolbox. - - :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: - """ + @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, @@ -7485,14 +7939,34 @@ async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: } 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.ToolboxObject] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreSearchResult] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_request( + 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, ) @@ -7525,47 +7999,24 @@ async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) + deserialized = _deserialize(_models.MemoryStoreSearchResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( + async def _update_memories_initial( self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = 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) - + ) -> AsyncIterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -7574,158 +8025,266 @@ def list( } 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_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), + 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, } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request + 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 - 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) + _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) - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + _decompress = kwargs.pop("decompress", True) + _stream = True + 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 + + 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, ) - 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) - 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")) - return pipeline_response + deserialized = response.iter_bytes() if _decompress else response.iter_raw() - return AsyncItemPaged(get_next, extract_data) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore - @distributed_trace - def list_versions( + return deserialized # type: ignore + + @overload + async def _begin_update_memories( self, name: str, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + 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 - ) -> AsyncItemPaged["_models.ToolboxVersionObject"]: - """List all versions of a toolbox. + ) -> 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]: ... - :param name: The name of the toolbox to list versions for. Required. + @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 - :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 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 = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(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( + 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, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, + 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 ) - 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 + await raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ToolboxVersionObject], - deserialized.get("data", []), + 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: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs + if polling is True: + polling_method: AsyncPollingMethod = cast( + AsyncPollingMethod, + AsyncLROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs), ) - response = pipeline_response.http_response + 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 + ) - 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) + @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. - return pipeline_response + :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 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 + :raises ~azure.core.exceptions.HttpResponseError: + """ - return AsyncItemPaged(get_next, extract_data) + @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. + + :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 + :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. + + :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 + :raises ~azure.core.exceptions.HttpResponseError: + """ @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 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: The name of the toolbox. Required. + :param name: The name of the memory store. 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 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 = { @@ -7736,15 +8295,29 @@ async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.T } 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.ToolboxVersionObject] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreDeleteScopeResult] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_version_request( + 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)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_memory_stores_delete_scope_request( name=name, - version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -7777,7 +8350,7 @@ 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.MemoryStoreDeleteScopeResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -7785,75 +8358,4218 @@ async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.T return deserialized # type: ignore @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_memory( + self, + name: str, + *, + scope: str, + content: str, + kind: Union[str, _models.MemoryItemKind], + content_type: str = "application/json", + **kwargs: Any + ) -> _models.MemoryItem: + """Create a memory item in a memory store. - :param name: The name of the toolbox to update. Required. + :param name: The name of the memory store. 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 scope: The namespace that logically groups and isolates memories, such as a user ID. + Required. + :paramtype scope: str + :keyword content: The content of the memory. Required. + :paramtype content: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Required. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind :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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update( + async def create_memory( self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + ) -> _models.MemoryItem: + """Create a memory item in 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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_memory( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Create a memory item in 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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_memory( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + content: str = _Unset, + kind: Union[str, _models.MemoryItemKind] = _Unset, + **kwargs: Any + ) -> _models.MemoryItem: + """Create a memory item in 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, such as a user ID. + Required. + :paramtype scope: str + :keyword content: The content of the memory. Required. + :paramtype content: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Required. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :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.MemoryItem] = kwargs.pop("cls", None) + + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + if content is _Unset: + raise TypeError("missing required argument: content") + if kind is _Unset: + raise TypeError("missing required argument: kind") + body = {"content": content, "kind": kind, "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_create_memory_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.MemoryItem, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + async def update_memory( + self, name: str, memory_id: str, *, content: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to update. Required. + :type memory_id: str + :keyword content: The updated content of the memory. Required. + :paramtype content: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update_memory( + self, name: str, memory_id: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to update. Required. + :type memory_id: 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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update_memory( + self, name: str, memory_id: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to update. Required. + :type memory_id: 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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def update_memory( + self, name: str, memory_id: str, body: Union[JSON, IO[bytes]] = _Unset, *, content: str = _Unset, **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to update. Required. + :type memory_id: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword content: The updated content of the memory. Required. + :paramtype content: str + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :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.MemoryItem] = kwargs.pop("cls", None) + + if body is _Unset: + if content is _Unset: + raise TypeError("missing required argument: content") + body = {"content": content} + 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_memory_request( + name=name, + memory_id=memory_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 [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.MemoryItem, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def get_memory(self, name: str, memory_id: str, **kwargs: Any) -> _models.MemoryItem: + """Retrieve a memory item from a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to retrieve. Required. + :type memory_id: str + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :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.MemoryItem] = kwargs.pop("cls", None) + + _request = build_beta_memory_stores_get_memory_request( + name=name, + memory_id=memory_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.MemoryItem, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def list_memories( + self, + name: str, + *, + scope: str, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> AsyncItemPaged["_models.MemoryItem"]: + """List all memory items in 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, such as a user ID. + Required. + :paramtype scope: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: An iterator like instance of MemoryItem + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.MemoryItem] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def list_memories( + self, + name: str, + body: JSON, + *, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> AsyncItemPaged["_models.MemoryItem"]: + """List all memory items in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param body: Required. + :type body: JSON + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: An iterator like instance of MemoryItem + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.MemoryItem] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def list_memories( + self, + name: str, + body: IO[bytes], + *, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> AsyncItemPaged["_models.MemoryItem"]: + """List all memory items in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: An iterator like instance of MemoryItem + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.MemoryItem] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def list_memories( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.MemoryItem"]: + """List all memory items in 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, such as a user ID. + Required. + :paramtype scope: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 MemoryItem + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.MemoryItem] + :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[List[_models.MemoryItem]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + # BUG? These lines were inside the prepare_request() method. Moved here instead. + 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)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + def prepare_request(_continuation_token=None): + + _request = build_beta_memory_stores_list_memories_request( + name=name, + kind=kind, + limit=limit, + order=order, + after=_continuation_token, + before=before, + 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) + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.MemoryItem], + 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_memory(self, name: str, memory_id: str, **kwargs: Any) -> _models.DeleteMemoryResult: + """Delete a memory item from a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to delete. Required. + :type memory_id: str + :return: DeleteMemoryResult. The DeleteMemoryResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteMemoryResult + :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.DeleteMemoryResult] = kwargs.pop("cls", None) + + _request = build_beta_memory_stores_delete_memory_request( + name=name, + memory_id=memory_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.DeleteMemoryResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +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. + :type name: str + :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, + 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 + + return AsyncItemPaged(get_next, extract_data) + + @distributed_trace + def list(self, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: + """List the latest version of each ModelVersion. + + :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, + 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, + 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 + + return AsyncItemPaged(get_next, extract_data) + + @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. + + :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 = 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.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. + + :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 = 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 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 pending_create_version( + self, + name: str, + version: str, + model_version: _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 model_version: Model version to create. Required. + :type model_version: ~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 pending_create_version( + self, name: str, version: str, model_version: 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 model_version: Model version to create. Required. + :type model_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: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def pending_create_version( + self, + name: str, + version: str, + model_version: 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 model_version: Model version to create. Required. + :type model_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: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def pending_create_version( + self, name: str, version: str, model_version: 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 name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param model_version: Model version to create. Is one of the following types: ModelVersion, + JSON, IO[bytes] Required. + :type model_version: ~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 = { + 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.CreateAsyncResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(model_version, (IOBase, bytes)): + _content = model_version + else: + _content = json.dumps(model_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_pending_create_version_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 [202]: + 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) + + 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.CreateAsyncResponse, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @overload + async def pending_upload( + self, + name: str, + version: str, + pending_upload_request: _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 pending_upload_request: Required. + :type pending_upload_request: ~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 + async def pending_upload( + self, + name: str, + version: str, + pending_upload_request: 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 pending_upload_request: Required. + :type pending_upload_request: 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, + pending_upload_request: 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 pending_upload_request: Required. + :type pending_upload_request: 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, + pending_upload_request: 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 pending_upload_request: Is one of the following types: ModelPendingUploadRequest, JSON, + IO[bytes] Required. + :type pending_upload_request: ~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, + 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.ModelPendingUploadResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(pending_upload_request, (IOBase, bytes)): + _content = pending_upload_request + else: + _content = json.dumps(pending_upload_request, 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.ModelPendingUploadResponse, 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, + credential_request: _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 credential_request: Required. + :type credential_request: ~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, + credential_request: 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 credential_request: Required. + :type credential_request: 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, + credential_request: 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 credential_request: Required. + :type credential_request: 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, + credential_request: 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 credential_request: Is one of the following types: ModelCredentialRequest, JSON, + IO[bytes] Required. + :type credential_request: ~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(credential_request, (IOBase, bytes)): + _content = credential_request + else: + _content = json.dumps(credential_request, 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, + 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.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 BetaRoutinesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`routines` 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_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 + async 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 + async 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_async + async 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 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 = { + 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.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 + + _request = build_beta_routines_create_or_update_request( + routine_name=routine_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.Routine, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Retrieve a routine. + + :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 = { + 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.Routine] = kwargs.pop("cls", None) + + _request = build_beta_routines_get_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) + + _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.Routine, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def enable(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Enable a routine. + + :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 = { + 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.Routine] = kwargs.pop("cls", None) + + _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) + + _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.Routine, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Disable a routine. + + :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 = { + 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.Routine] = kwargs.pop("cls", None) + + _request = build_beta_routines_disable_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) + + _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.Routine, 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.Routine"]: + """List routines. + + :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.async_paging.AsyncItemPaged[~azure.ai.projects.models.Routine] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.Routine]] = 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_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.Routine], + 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(self, routine_name: str, **kwargs: Any) -> None: + """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 = 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 + + @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 + ) -> AsyncItemPaged["_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.async_paging.AsyncItemPaged[~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 + + async 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, 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 dispatch( + self, + routine_name: str, + *, + content_type: str = "application/json", + payload: Optional[_models.RoutineDispatchPayload] = None, + **kwargs: Any + ) -> _models.DispatchRoutineResult: + """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 + :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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def dispatch( + self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DispatchRoutineResult: + """Queue an asynchronous routine dispatch. + + :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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def dispatch( + self, routine_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DispatchRoutineResult: + """Queue an asynchronous routine dispatch. + + :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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def dispatch( + self, + routine_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + payload: Optional[_models.RoutineDispatchPayload] = None, + **kwargs: Any + ) -> _models.DispatchRoutineResult: + """Queue an asynchronous routine dispatch. + + :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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult + :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.DispatchRoutineResult] = 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(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_routines_dispatch_request( + routine_name=routine_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.DispatchRoutineResult, 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, + } + 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, + ) + 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.Schedule, 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.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.Schedule"]: + """List all schedules. + + :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] + :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, + 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_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) + + return _request + + 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) + + 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_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 + 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, + 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 = 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.Schedule, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: + """Get a schedule run by id. + + :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 = { + 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.ScheduleRun] = kwargs.pop("cls", None) + + _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, + ) + 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.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 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. 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 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 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 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: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :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. + + :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: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :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. + + :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 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 = { + 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.ToolboxVersionObject] = 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 + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_toolboxes_create_version_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.ToolboxVersionObject, 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.ToolboxObject: + """Retrieve a toolbox. + + :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 = { + 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.ToolboxObject] = kwargs.pop("cls", None) + + _request = build_beta_toolboxes_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) + 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.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 + ) -> 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 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 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 = { + 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.ToolboxVersionObject] = kwargs.pop("cls", None) + + _request = build_beta_toolboxes_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) + 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.ToolboxVersionObject, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @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. + + :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 + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + 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: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + 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: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject + :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. + + :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 + :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.ToolboxObject] = 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} + 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_toolboxes_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.ToolboxObject, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def delete(self, name: str, **kwargs: Any) -> None: + """Delete a toolbox and all its versions. + + :param name: The name of the toolbox to delete. Required. + :type 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_toolboxes_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) + + _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 + + @distributed_trace_async + async def delete_version(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 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_toolboxes_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) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + +class BetaSkillsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`skills` 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( + 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. + + :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 + :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( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Creates a skill. + + :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 + :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. + + :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 + :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. + + :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 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 - :raises ~azure.core.exceptions.HttpResponseError: - """ + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) - @overload - 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. + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - :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 - :raises ~azure.core.exceptions.HttpResponseError: - """ + return deserialized # type: ignore @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_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: + """Creates a skill from a zip package. - :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 + :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 = { @@ -7867,23 +12583,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)) - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", 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: - 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 - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = content - _request = build_beta_toolboxes_update_request( - name=name, + _request = build_beta_skills_create_from_package_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7903,7 +12608,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 @@ -7919,7 +12624,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.SkillDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -7927,13 +12632,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.SkillDetails: + """Retrieves a skill. - :param name: The name of the toolbox to delete. Required. + :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 = { @@ -7947,9 +12652,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.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, @@ -7960,14 +12665,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, @@ -7975,19 +12686,24 @@ 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.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_async - async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: - """Delete a specific version of a toolbox. + async def download(self, name: str, **kwargs: Any) -> AsyncIterator[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: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8001,11 +12717,10 @@ 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[AsyncIterator[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, @@ -8015,14 +12730,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", 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, @@ -8030,42 +12751,121 @@ async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: ) 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 + ) -> AsyncItemPaged["_models.SkillDetails"]: + """Returns the list of all skills. - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.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.async_paging.AsyncItemPaged[~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: 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[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) + + _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( + async 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.SkillObject: - """Creates a skill. + ) -> _models.SkillDetails: + """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 @@ -8081,58 +12881,64 @@ async def create( 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillObject: - """Creates a skill. + 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create( - self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillObject: - """Creates a skill. + async 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. Default value is "application/json". :paramtype content_type: str - :return: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :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( + async 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.SkillObject: - """Creates a skill. + ) -> _models.SkillDetails: + """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 @@ -8145,8 +12951,8 @@ async def create( 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8161,12 +12967,10 @@ async def create( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillObject] = kwargs.pop("cls", 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 = {"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 @@ -8175,76 +12979,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.SkillObject, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace_async - async def create_from_package(self, body: bytes, **kwargs: Any) -> _models.SkillObject: - """Creates a skill from a zip package. - - :param body: The zip package used to create the skill. Required. - :type body: bytes - :return: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject - :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.SkillObject] = kwargs.pop("cls", None) - - _content = body - - _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, @@ -8264,7 +13000,7 @@ async def create_from_package(self, body: bytes, **kwargs: Any) -> _models.Skill 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 @@ -8280,7 +13016,7 @@ async def create_from_package(self, body: bytes, **kwargs: Any) -> _models.Skill if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillObject, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -8288,13 +13024,13 @@ async def create_from_package(self, body: bytes, **kwargs: Any) -> _models.Skill return deserialized # type: ignore @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.SkillObject: - """Retrieves a skill. + async 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8308,9 +13044,9 @@ async def get(self, name: str, **kwargs: Any) -> _models.SkillObject: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillObject] = 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, @@ -8345,21 +13081,41 @@ async def get(self, name: str, **kwargs: Any) -> _models.SkillObject: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillObject, 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.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 download(self, name: str, **kwargs: Any) -> AsyncIterator[bytes]: - """Downloads a skill package. + async 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: AsyncIterator[bytes] - :rtype: AsyncIterator[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 = { @@ -8373,10 +13129,10 @@ 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[_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, @@ -8387,7 +13143,7 @@ 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 = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -8408,9 +13164,12 @@ 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")) + 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 @@ -8418,15 +13177,19 @@ async def download(self, name: str, **kwargs: Any) -> AsyncIterator[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 - ) -> AsyncItemPaged["_models.SkillObject"]: - """Returns the list of all skills. + ) -> 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 @@ -8442,14 +13205,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 SkillObject - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.SkillObject] + :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.SkillObject]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.DataGenerationJob]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -8461,11 +13229,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, @@ -8479,7 +13249,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.SkillObject], + List[_models.DataGenerationJob], deserialized.get("data", []), ) if cls: @@ -8508,107 +13278,98 @@ async def get_next(_continuation_token=None): return AsyncItemPaged(get_next, extract_data) @overload - async def update( + async 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.SkillObject: - """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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillObject: - """Updates an existing skill. - - :param name: The unique name of the skill. Required. - :type name: str - :param body: Required. - :type body: JSON + 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillObject: - """Updates an existing skill. + 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. - :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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def update( + async 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.SkillObject: - """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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :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 = { @@ -8623,20 +13384,17 @@ async def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillObject] = 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, @@ -8656,7 +13414,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 @@ -8669,24 +13427,30 @@ async 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.SkillObject, 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_async - async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResponse: - """Deletes a skill. + async 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: DeleteSkillResponse. The DeleteSkillResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillResponse + 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 = { @@ -8700,10 +13464,10 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResponse: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteSkillResponse] = 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, @@ -8737,9 +13501,63 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResponse: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteSkillResponse, response.json()) + 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/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index 56dea6851b0d..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 @@ -15,14 +15,17 @@ 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 ( + BetaDatasetsOperations, BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, BetaOperations as GeneratedBetaOperations, BetaRedTeamsOperations, + BetaRoutinesOperations, BetaSchedulesOperations, BetaSkillsOperations, BetaToolboxesOperations, @@ -49,14 +52,20 @@ class BetaOperations(GeneratedBetaOperations): """:class:`~azure.ai.projects.aio.operations.BetaInsightsOperations` operations""" memory_stores: BetaMemoryStoresOperations """:class:`~azure.ai.projects.aio.operations.BetaMemoryStoresOperations` operations""" + models: BetaModelsOperations + """:class:`~azure.ai.projects.aio.operations.BetaModelsOperations` operations""" red_teams: BetaRedTeamsOperations """:class:`~azure.ai.projects.aio.operations.BetaRedTeamsOperations` operations""" + routines: BetaRoutinesOperations + """:class:`~azure.ai.projects.aio.operations.BetaRoutinesOperations` operations""" schedules: BetaSchedulesOperations """:class:`~azure.ai.projects.aio.operations.BetaSchedulesOperations` operations""" toolboxes: BetaToolboxesOperations """: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) @@ -66,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 (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( @@ -78,12 +89,15 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: __all__: List[str] = [ "AgentsOperations", "BetaAgentsOperations", + "BetaDatasetsOperations", "BetaEvaluationTaxonomiesOperations", "BetaEvaluatorsOperations", "BetaInsightsOperations", "BetaMemoryStoresOperations", + "BetaModelsOperations", "BetaOperations", "BetaRedTeamsOperations", + "BetaRoutinesOperations", "BetaSchedulesOperations", "BetaSkillsOperations", "BetaToolboxesOperations", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py index f2a6dbc62624..46a4d7a9e456 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_agents_async.py @@ -13,8 +13,9 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ._operations import AgentsOperations as GeneratedAgentsOperations, JSON, _Unset from ... import models as _models -from ...models._patch import _FOUNDRY_FEATURES_HEADER_NAME, _has_header_case_insensitive -from ...operations._patch_agents import ( +from ...models._patch import ( + _FOUNDRY_FEATURES_HEADER_NAME, + _has_header_case_insensitive, _AGENT_OPERATION_FEATURE_HEADERS, _PREVIEW_FEATURE_REQUIRED_CODE, _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE, @@ -40,6 +41,7 @@ async def create_version( content_type: str = "application/json", metadata: Optional[dict[str, str]] = None, description: Optional[str] = None, + blueprint_reference: Optional[_models.AgentBlueprintReference] = None, **kwargs: Any, ) -> _models.AgentVersionDetails: """Create a new agent version. @@ -66,6 +68,8 @@ async def create_version( :paramtype metadata: dict[str, str] :keyword description: A human-readable description of the agent. Default value is None. :paramtype description: str + :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. + :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping :rtype: ~azure.ai.projects.models.AgentVersionDetails :raises ~azure.core.exceptions.HttpResponseError: @@ -129,6 +133,7 @@ async def create_version( definition: _models.AgentDefinition = _Unset, metadata: Optional[dict[str, str]] = None, description: Optional[str] = None, + blueprint_reference: Optional[_models.AgentBlueprintReference] = None, **kwargs: Any, ) -> _models.AgentVersionDetails: """Create a new agent version. @@ -154,6 +159,8 @@ async def create_version( :paramtype metadata: dict[str, str] :keyword description: A human-readable description of the agent. Default value is None. :paramtype description: str + :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. + :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping :rtype: ~azure.ai.projects.models.AgentVersionDetails :raises ~azure.core.exceptions.HttpResponseError: @@ -174,6 +181,7 @@ async def create_version( definition=definition, metadata=metadata, description=description, + blueprint_reference=blueprint_reference, **kwargs, ) except HttpResponseError as exc: diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_evaluation_rules_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_evaluation_rules_async.py index a296493c469b..7e61eeb2866c 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_evaluation_rules_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_evaluation_rules_async.py @@ -13,9 +13,13 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ._operations import EvaluationRulesOperations as GeneratedEvaluationRulesOperations, JSON from ... import models as _models -from ...operations._patch_agents import _PREVIEW_FEATURE_REQUIRED_CODE, _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE from ...models._enums import _FoundryFeaturesOptInKeys -from ...models._patch import _FOUNDRY_FEATURES_HEADER_NAME, _has_header_case_insensitive +from ...models._patch import ( + _FOUNDRY_FEATURES_HEADER_NAME, + _has_header_case_insensitive, + _PREVIEW_FEATURE_REQUIRED_CODE, + _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE, +) class EvaluationRulesOperations(GeneratedEvaluationRulesOperations): 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..b40c7922b4f6 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py @@ -0,0 +1,331 @@ +# 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 # pylint: disable=do-not-import-asyncio +import logging +import os +from pathlib import Path +from typing import Any, Literal, Optional, Union, overload + +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. + + :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 = 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") + 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_inputs( + *, + name: str, + version: str, + source: Union[str, "os.PathLike[str]"], + wait_for_commit: bool, + polling_timeout: float, + polling_interval: float, + ) -> Path: + """Validate ``create`` inputs up-front, before any service call. + + 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.") + 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``. + + :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: + 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` 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] 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] uploaded %s (%d bytes)", rel, f.stat().st_size) + + @overload + async def create( + 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: Literal[True] = True, + polling_timeout: float = 300.0, + polling_interval: float = 2.0, + **kwargs: Any, + ) -> ModelVersion: + ... + + @overload + async def create( + 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: Literal[False], + polling_timeout: float = 300.0, + polling_interval: float = 2.0, + **kwargs: Any, + ) -> None: + ... + + @distributed_trace_async + async def create( + 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_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] step 1/3 pending_upload(name=%r, version=%r)", + name, + version, + ) + pending = await self.pending_upload( + name=name, + version=version, + pending_upload_request=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] pending_upload_id=%s blob_uri=%s", + pending_upload_id, + container_blob_uri, + ) + + # --- Step 2: Upload via async ContainerClient ------------------------ + 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 ------------------------------------- + model_version_body = ModelVersion( + blob_uri=container_blob_uri, + weight_type=weight_type, + base_model=base_model, + description=description, + tags=tags or {}, + ) + logger.info( + "[create] step 3/3 pending_create_version(name=%r, version=%r)", + name, + version, + ) + await self.pending_create_version(name=name, version=version, model_version=model_version_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/aio/operations/_patch_sessions_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_sessions_async.py index c4257fec3242..dd1427541a65 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_sessions_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_sessions_async.py @@ -34,7 +34,7 @@ async def upload_session_file( # type: ignore[override] *, path: str, **kwargs: Any, - ) -> _models.SessionFileWriteResponse: + ) -> _models.SessionFileWriteResult: """Upload a file to the session sandbox. Accepts either a ``bytes`` buffer or a local file path (``str``). @@ -52,9 +52,9 @@ async def upload_session_file( # type: ignore[override] :keyword path: The destination file path within the sandbox, relative to the session home directory. Required. :paramtype path: str - :return: SessionFileWriteResponse. The SessionFileWriteResponse is compatible with + :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionFileWriteResponse + :rtype: ~azure.ai.projects.models.SessionFileWriteResult :raises ~azure.core.exceptions.HttpResponseError: :raises FileNotFoundError: If *content_or_file_path* is a ``str`` and the file does not exist. """ 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 8dfca8b30a03..18cf2f3c5d96 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,21 +21,25 @@ AgentCardSkill, AgentClusterInsightRequest, AgentClusterInsightResult, + AgentDataGenerationJobSource, AgentDefinition, AgentDetails, - AgentEndpoint, AgentEndpointAuthorizationScheme, + AgentEndpointConfig, + AgentEvaluatorGenerationJobSource, AgentIdentity, AgentObjectVersions, AgentSessionResource, AgentTaxonomyInput, AgentVersionDetails, AgenticIdentityPreviewCredentials, + AgentsPagedResultOptimizationCandidate, ApiError, ApiErrorResponse, ApiKeyCredentials, ApplyPatchToolParam, ApproximateLocation, + ArtifactProfile, AutoCodeInterpreterToolParam, AzureAIAgentTarget, AzureAIModelTarget, @@ -62,6 +66,8 @@ BrowserAutomationPreviewTool, BrowserAutomationToolConnectionParameters, BrowserAutomationToolParameters, + CandidateDeployConfig, + CandidateResults, CaptureStructuredOutputsTool, ChartCoordinate, ChatSummaryMemoryItem, @@ -83,6 +89,9 @@ ContainerSkill, ContinuousEvaluationRuleAction, CosmosDBIndex, + CreateAgentVersionFromCodeContent, + CreateAgentVersionFromCodeMetadata, + CreateAsyncResponse, CronTrigger, CustomCredential, CustomGrammarFormatParam, @@ -90,23 +99,43 @@ CustomToolParam, CustomToolParamFormat, DailyRecurrenceSchedule, + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOptions, + DataGenerationJobOutput, + DataGenerationJobOutputOptions, + DataGenerationJobResult, + DataGenerationJobSource, + DataGenerationModelOptions, + DataGenerationTokenUsage, DatasetCredential, + DatasetDataGenerationJobOutput, + DatasetDataGenerationJobSource, + DatasetEvaluatorGenerationJobSource, + DatasetItem, + DatasetRef, + DatasetReference, DatasetVersion, DeleteAgentResponse, DeleteAgentVersionResponse, + DeleteMemoryResult, DeleteMemoryStoreResult, - DeleteSkillResponse, + DeleteSkillResult, Deployment, + Dimension, + DispatchRoutineResult, EmbeddingConfiguration, EntraAuthorizationScheme, EntraIDCredentials, EntraIsolationKeySource, EvalResult, + EvalRunOutputItemResult, EvalRunResultCompareItem, EvalRunResultComparison, EvalRunResultSummary, EvaluationComparisonInsightRequest, EvaluationComparisonInsightResult, + EvaluationCriterion, EvaluationResultSample, EvaluationRule, EvaluationRuleAction, @@ -114,22 +143,35 @@ EvaluationRunClusterInsightRequest, EvaluationRunClusterInsightResult, EvaluationScheduleTask, + EvaluationTarget, EvaluationTaxonomy, EvaluationTaxonomyInput, + EvaluatorCredentialRequest, EvaluatorDefinition, + EvaluatorGenerationArtifacts, + EvaluatorGenerationInputs, + EvaluatorGenerationJob, + EvaluatorGenerationJobSource, + EvaluatorGenerationTokenUsage, EvaluatorMetric, EvaluatorVersion, + ExternalAgentDefinition, FabricDataAgentToolParameters, + FabricIQPreviewTool, FieldMapping, + FileDataGenerationJobOutput, + FileDataGenerationJobSource, FileDatasetVersion, FileSearchTool, FixedRatioVersionSelectionRule, FolderDatasetVersion, + FoundryModelWarning, FunctionShellToolParam, FunctionShellToolParamEnvironment, FunctionShellToolParamEnvironmentContainerReferenceParam, FunctionShellToolParamEnvironmentLocalEnvironmentParam, FunctionTool, + GitHubIssueOpenedRoutineTrigger, HeaderIsolationKeySource, HeaderTelemetryEndpointAuth, HostedAgentDefinition, @@ -150,9 +192,14 @@ InsightScheduleTask, InsightSummary, InsightsMetadata, + InvokeAgentInvocationsApiDispatchPayload, + InvokeAgentInvocationsApiRoutineAction, + InvokeAgentResponsesApiDispatchPayload, + InvokeAgentResponsesApiRoutineAction, IsolationKeySource, LocalShellToolParam, LocalSkillParam, + LoraConfig, MCPTool, MCPToolFilter, MCPToolRequireApproval, @@ -173,9 +220,14 @@ MemoryStoreUpdateCompletedResult, MemoryStoreUpdateResult, MicrosoftFabricPreviewTool, + ModelCredentialRequest, ModelDeployment, ModelDeploymentSku, + ModelPendingUploadRequest, + ModelPendingUploadResponse, ModelSamplingParams, + ModelSourceData, + ModelVersion, MonthlyRecurrenceSchedule, NoAuthenticationCredentials, OneTimeTrigger, @@ -188,12 +240,24 @@ OpenApiProjectConnectionAuthDetails, OpenApiProjectConnectionSecurityScheme, OpenApiTool, + OptimizationAgentDefinition, + OptimizationAgentSkill, + OptimizationCandidate, + OptimizationJob, + OptimizationJobInputs, + OptimizationJobProgress, + OptimizationJobResult, + OptimizationOptions, + OptimizationTaskResult, OtlpTelemetryEndpoint, PendingUploadRequest, PendingUploadResponse, + ProceduralMemoryItem, PromptAgentDefinition, PromptAgentDefinitionTextOptions, PromptBasedEvaluatorDefinition, + PromptDataGenerationJobSource, + PromptEvaluatorGenerationJobSource, ProtocolVersionRecord, RaiConfig, RankingOptions, @@ -201,26 +265,35 @@ RecurrenceSchedule, RecurrenceTrigger, RedTeam, + RedTeamTargetConfig, ResponseUsageInputTokensDetails, ResponseUsageOutputTokensDetails, + Routine, + RoutineAction, + RoutineDispatchPayload, + RoutineRun, + RoutineRunDiagnostics, + RoutineTrigger, + RubricBasedEvaluatorDefinition, SASCredentials, Schedule, + ScheduleRoutineTrigger, ScheduleRun, ScheduleTask, SessionDirectoryEntry, - SessionDirectoryListResponse, - SessionFileWriteResponse, + SessionDirectoryListResult, + SessionFileWriteResult, SessionLogEvent, SharepointGroundingToolParameters, SharepointPreviewTool, - SkillObject, + SimpleQnADataGenerationJobOptions, + SkillDetails, SkillReferenceParam, SpecificApplyPatchParam, SpecificFunctionShellParam, StructuredInputDefinition, StructuredOutputDefinition, - Target, - TargetConfig, + SystemDataV3, TaxonomyCategory, TaxonomySubCategory, TelemetryConfig, @@ -230,6 +303,7 @@ TextResponseFormatJsonObject, TextResponseFormatJsonSchema, TextResponseFormatText, + TimerRoutineTrigger, Tool, ToolChoiceAllowed, ToolChoiceCodeInterpreter, @@ -242,12 +316,19 @@ ToolChoiceParam, ToolChoiceWebSearchPreview, ToolChoiceWebSearchPreview20250311, + ToolConfig, ToolDescription, ToolProjectConnection, + ToolUseFineTuningDataGenerationJobOptions, ToolboxObject, ToolboxPolicies, + ToolboxSearchPreviewTool, ToolboxVersionObject, + TracesDataGenerationJobOptions, + TracesDataGenerationJobSource, + TracesEvaluatorGenerationJobSource, Trigger, + UpdateModelVersionRequest, UpdateToolboxRequest, UserProfileMemoryItem, VersionIndicator, @@ -261,7 +342,6 @@ WebSearchToolFilters, WeeklyRecurrenceSchedule, WorkIQPreviewTool, - WorkIQPreviewToolParameters, WorkflowAgentDefinition, ) @@ -276,6 +356,7 @@ AgentVersionStatus, AttackStrategy, AzureAISearchQueryType, + CodeDependencyResolution, ComputerEnvironment, ConnectionType, ContainerMemoryLimit, @@ -283,17 +364,28 @@ ContainerSkillType, CredentialType, CustomToolParamFormatType, + DataGenerationJobOutputType, + DataGenerationJobScenario, + DataGenerationJobSourceType, + DataGenerationJobType, DatasetType, DayOfWeek, DeploymentType, + EvalRunOutputItemResultStatus, EvaluationRuleActionType, EvaluationRuleEventType, EvaluationTaxonomyInputType, EvaluatorCategory, EvaluatorDefinitionType, + EvaluatorGenerationJobSourceType, EvaluatorMetricDirection, EvaluatorMetricType, EvaluatorType, + FoundryModelArtifactProfileCategory, + FoundryModelArtifactProfileSignal, + FoundryModelSourceType, + FoundryModelWarningCode, + FoundryModelWeightType, FunctionShellToolParamEnvironmentType, GrammarSyntax1, ImageGenAction, @@ -301,6 +393,7 @@ InputFidelity, InsightType, IsolationKeySourceKind, + JobStatus, MemoryItemKind, MemoryOperationKind, MemoryStoreKind, @@ -308,16 +401,24 @@ MemoryStoreUpdateStatus, OpenApiAuthType, OperationState, + OptimizationMode, + OptimizationStrategy, PageOrder, PendingUploadType, RankerVersionType, RecurrenceType, RiskCategory, + RoutineActionType, + RoutineAttemptSource, + RoutineDispatchPayloadType, + RoutineRunPhase, + RoutineTriggerType, SampleType, ScheduleProvisioningStatus, ScheduleTaskType, SearchContextSize, SessionLogEventType, + SimpleQnAFineTuningQuestionType, TelemetryDataKind, TelemetryEndpointAuthType, TelemetryEndpointKind, @@ -342,21 +443,25 @@ "AgentCardSkill", "AgentClusterInsightRequest", "AgentClusterInsightResult", + "AgentDataGenerationJobSource", "AgentDefinition", "AgentDetails", - "AgentEndpoint", "AgentEndpointAuthorizationScheme", + "AgentEndpointConfig", + "AgentEvaluatorGenerationJobSource", "AgentIdentity", "AgentObjectVersions", "AgentSessionResource", "AgentTaxonomyInput", "AgentVersionDetails", "AgenticIdentityPreviewCredentials", + "AgentsPagedResultOptimizationCandidate", "ApiError", "ApiErrorResponse", "ApiKeyCredentials", "ApplyPatchToolParam", "ApproximateLocation", + "ArtifactProfile", "AutoCodeInterpreterToolParam", "AzureAIAgentTarget", "AzureAIModelTarget", @@ -383,6 +488,8 @@ "BrowserAutomationPreviewTool", "BrowserAutomationToolConnectionParameters", "BrowserAutomationToolParameters", + "CandidateDeployConfig", + "CandidateResults", "CaptureStructuredOutputsTool", "ChartCoordinate", "ChatSummaryMemoryItem", @@ -404,6 +511,9 @@ "ContainerSkill", "ContinuousEvaluationRuleAction", "CosmosDBIndex", + "CreateAgentVersionFromCodeContent", + "CreateAgentVersionFromCodeMetadata", + "CreateAsyncResponse", "CronTrigger", "CustomCredential", "CustomGrammarFormatParam", @@ -411,23 +521,43 @@ "CustomToolParam", "CustomToolParamFormat", "DailyRecurrenceSchedule", + "DataGenerationJob", + "DataGenerationJobInputs", + "DataGenerationJobOptions", + "DataGenerationJobOutput", + "DataGenerationJobOutputOptions", + "DataGenerationJobResult", + "DataGenerationJobSource", + "DataGenerationModelOptions", + "DataGenerationTokenUsage", "DatasetCredential", + "DatasetDataGenerationJobOutput", + "DatasetDataGenerationJobSource", + "DatasetEvaluatorGenerationJobSource", + "DatasetItem", + "DatasetRef", + "DatasetReference", "DatasetVersion", "DeleteAgentResponse", "DeleteAgentVersionResponse", + "DeleteMemoryResult", "DeleteMemoryStoreResult", - "DeleteSkillResponse", + "DeleteSkillResult", "Deployment", + "Dimension", + "DispatchRoutineResult", "EmbeddingConfiguration", "EntraAuthorizationScheme", "EntraIDCredentials", "EntraIsolationKeySource", "EvalResult", + "EvalRunOutputItemResult", "EvalRunResultCompareItem", "EvalRunResultComparison", "EvalRunResultSummary", "EvaluationComparisonInsightRequest", "EvaluationComparisonInsightResult", + "EvaluationCriterion", "EvaluationResultSample", "EvaluationRule", "EvaluationRuleAction", @@ -435,22 +565,35 @@ "EvaluationRunClusterInsightRequest", "EvaluationRunClusterInsightResult", "EvaluationScheduleTask", + "EvaluationTarget", "EvaluationTaxonomy", "EvaluationTaxonomyInput", + "EvaluatorCredentialRequest", "EvaluatorDefinition", + "EvaluatorGenerationArtifacts", + "EvaluatorGenerationInputs", + "EvaluatorGenerationJob", + "EvaluatorGenerationJobSource", + "EvaluatorGenerationTokenUsage", "EvaluatorMetric", "EvaluatorVersion", + "ExternalAgentDefinition", "FabricDataAgentToolParameters", + "FabricIQPreviewTool", "FieldMapping", + "FileDataGenerationJobOutput", + "FileDataGenerationJobSource", "FileDatasetVersion", "FileSearchTool", "FixedRatioVersionSelectionRule", "FolderDatasetVersion", + "FoundryModelWarning", "FunctionShellToolParam", "FunctionShellToolParamEnvironment", "FunctionShellToolParamEnvironmentContainerReferenceParam", "FunctionShellToolParamEnvironmentLocalEnvironmentParam", "FunctionTool", + "GitHubIssueOpenedRoutineTrigger", "HeaderIsolationKeySource", "HeaderTelemetryEndpointAuth", "HostedAgentDefinition", @@ -471,9 +614,14 @@ "InsightScheduleTask", "InsightSummary", "InsightsMetadata", + "InvokeAgentInvocationsApiDispatchPayload", + "InvokeAgentInvocationsApiRoutineAction", + "InvokeAgentResponsesApiDispatchPayload", + "InvokeAgentResponsesApiRoutineAction", "IsolationKeySource", "LocalShellToolParam", "LocalSkillParam", + "LoraConfig", "MCPTool", "MCPToolFilter", "MCPToolRequireApproval", @@ -494,9 +642,14 @@ "MemoryStoreUpdateCompletedResult", "MemoryStoreUpdateResult", "MicrosoftFabricPreviewTool", + "ModelCredentialRequest", "ModelDeployment", "ModelDeploymentSku", + "ModelPendingUploadRequest", + "ModelPendingUploadResponse", "ModelSamplingParams", + "ModelSourceData", + "ModelVersion", "MonthlyRecurrenceSchedule", "NoAuthenticationCredentials", "OneTimeTrigger", @@ -509,12 +662,24 @@ "OpenApiProjectConnectionAuthDetails", "OpenApiProjectConnectionSecurityScheme", "OpenApiTool", + "OptimizationAgentDefinition", + "OptimizationAgentSkill", + "OptimizationCandidate", + "OptimizationJob", + "OptimizationJobInputs", + "OptimizationJobProgress", + "OptimizationJobResult", + "OptimizationOptions", + "OptimizationTaskResult", "OtlpTelemetryEndpoint", "PendingUploadRequest", "PendingUploadResponse", + "ProceduralMemoryItem", "PromptAgentDefinition", "PromptAgentDefinitionTextOptions", "PromptBasedEvaluatorDefinition", + "PromptDataGenerationJobSource", + "PromptEvaluatorGenerationJobSource", "ProtocolVersionRecord", "RaiConfig", "RankingOptions", @@ -522,26 +687,35 @@ "RecurrenceSchedule", "RecurrenceTrigger", "RedTeam", + "RedTeamTargetConfig", "ResponseUsageInputTokensDetails", "ResponseUsageOutputTokensDetails", + "Routine", + "RoutineAction", + "RoutineDispatchPayload", + "RoutineRun", + "RoutineRunDiagnostics", + "RoutineTrigger", + "RubricBasedEvaluatorDefinition", "SASCredentials", "Schedule", + "ScheduleRoutineTrigger", "ScheduleRun", "ScheduleTask", "SessionDirectoryEntry", - "SessionDirectoryListResponse", - "SessionFileWriteResponse", + "SessionDirectoryListResult", + "SessionFileWriteResult", "SessionLogEvent", "SharepointGroundingToolParameters", "SharepointPreviewTool", - "SkillObject", + "SimpleQnADataGenerationJobOptions", + "SkillDetails", "SkillReferenceParam", "SpecificApplyPatchParam", "SpecificFunctionShellParam", "StructuredInputDefinition", "StructuredOutputDefinition", - "Target", - "TargetConfig", + "SystemDataV3", "TaxonomyCategory", "TaxonomySubCategory", "TelemetryConfig", @@ -551,6 +725,7 @@ "TextResponseFormatJsonObject", "TextResponseFormatJsonSchema", "TextResponseFormatText", + "TimerRoutineTrigger", "Tool", "ToolChoiceAllowed", "ToolChoiceCodeInterpreter", @@ -563,12 +738,19 @@ "ToolChoiceParam", "ToolChoiceWebSearchPreview", "ToolChoiceWebSearchPreview20250311", + "ToolConfig", "ToolDescription", "ToolProjectConnection", + "ToolUseFineTuningDataGenerationJobOptions", "ToolboxObject", "ToolboxPolicies", + "ToolboxSearchPreviewTool", "ToolboxVersionObject", + "TracesDataGenerationJobOptions", + "TracesDataGenerationJobSource", + "TracesEvaluatorGenerationJobSource", "Trigger", + "UpdateModelVersionRequest", "UpdateToolboxRequest", "UserProfileMemoryItem", "VersionIndicator", @@ -582,7 +764,6 @@ "WebSearchToolFilters", "WeeklyRecurrenceSchedule", "WorkIQPreviewTool", - "WorkIQPreviewToolParameters", "WorkflowAgentDefinition", "AgentBlueprintReferenceType", "AgentEndpointAuthorizationSchemeType", @@ -594,6 +775,7 @@ "AgentVersionStatus", "AttackStrategy", "AzureAISearchQueryType", + "CodeDependencyResolution", "ComputerEnvironment", "ConnectionType", "ContainerMemoryLimit", @@ -601,17 +783,28 @@ "ContainerSkillType", "CredentialType", "CustomToolParamFormatType", + "DataGenerationJobOutputType", + "DataGenerationJobScenario", + "DataGenerationJobSourceType", + "DataGenerationJobType", "DatasetType", "DayOfWeek", "DeploymentType", + "EvalRunOutputItemResultStatus", "EvaluationRuleActionType", "EvaluationRuleEventType", "EvaluationTaxonomyInputType", "EvaluatorCategory", "EvaluatorDefinitionType", + "EvaluatorGenerationJobSourceType", "EvaluatorMetricDirection", "EvaluatorMetricType", "EvaluatorType", + "FoundryModelArtifactProfileCategory", + "FoundryModelArtifactProfileSignal", + "FoundryModelSourceType", + "FoundryModelWarningCode", + "FoundryModelWeightType", "FunctionShellToolParamEnvironmentType", "GrammarSyntax1", "ImageGenAction", @@ -619,6 +812,7 @@ "InputFidelity", "InsightType", "IsolationKeySourceKind", + "JobStatus", "MemoryItemKind", "MemoryOperationKind", "MemoryStoreKind", @@ -626,16 +820,24 @@ "MemoryStoreUpdateStatus", "OpenApiAuthType", "OperationState", + "OptimizationMode", + "OptimizationStrategy", "PageOrder", "PendingUploadType", "RankerVersionType", "RecurrenceType", "RiskCategory", + "RoutineActionType", + "RoutineAttemptSource", + "RoutineDispatchPayloadType", + "RoutineRunPhase", + "RoutineTriggerType", "SampleType", "ScheduleProvisioningStatus", "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 588927c00421..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 @@ -1,3 +1,4 @@ +# pylint: disable=too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. @@ -17,17 +18,17 @@ class _AgentDefinitionOptInKeys(str, Enum, metaclass=CaseInsensitiveEnumMeta): """HOSTED_AGENTS_V1_PREVIEW.""" WORKFLOW_AGENTS_V1_PREVIEW = "WorkflowAgents=V1Preview" """WORKFLOW_AGENTS_V1_PREVIEW.""" - CONTAINER_AGENTS_V1_PREVIEW = "ContainerAgents=V1Preview" - """CONTAINER_AGENTS_V1_PREVIEW.""" AGENT_ENDPOINT_V1_PREVIEW = "AgentEndpoints=V1Preview" """AGENT_ENDPOINT_V1_PREVIEW.""" + CODE_AGENTS_V1_PREVIEW = "CodeAgents=V1Preview" + """CODE_AGENTS_V1_PREVIEW.""" + EXTERNAL_AGENTS_V1_PREVIEW = "ExternalAgents=V1Preview" + """EXTERNAL_AGENTS_V1_PREVIEW.""" 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" @@ -38,8 +39,16 @@ class _FoundryFeaturesOptInKeys(str, Enum, metaclass=CaseInsensitiveEnumMeta): """INSIGHTS_V1_PREVIEW.""" MEMORY_STORES_V1_PREVIEW = "MemoryStores=V1Preview" """MEMORY_STORES_V1_PREVIEW.""" - TOOLBOXES_V1_PREVIEW = "Toolboxes=V1Preview" - """TOOLBOXES_V1_PREVIEW.""" + ROUTINES_V1_PREVIEW = "Routines=V1Preview" + """ROUTINES_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.""" + AGENTS_OPTIMIZATION_V1_PREVIEW = "AgentsOptimization=V1Preview" + """AGENTS_OPTIMIZATION_V1_PREVIEW.""" class AgentBlueprintReferenceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -69,6 +78,8 @@ class AgentEndpointProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """RESPONSES.""" A2A = "a2a" """A2A.""" + MCP = "mcp" + """MCP.""" INVOCATIONS = "invocations" """INVOCATIONS.""" @@ -82,6 +93,8 @@ class AgentKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """HOSTED.""" WORKFLOW = "workflow" """WORKFLOW.""" + EXTERNAL = "external" + """EXTERNAL.""" class AgentObjectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -106,6 +119,8 @@ class AgentProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """ACTIVITY_PROTOCOL.""" RESPONSES = "responses" """RESPONSES.""" + MCP = "mcp" + """MCP.""" INVOCATIONS = "invocations" """INVOCATIONS.""" @@ -232,6 +247,16 @@ class AzureAISearchQueryType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Query type ``vector_semantic_hybrid``.""" +class CodeDependencyResolution(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """How package dependencies are resolved at deployment time for a code-based hosted agent.""" + + BUNDLED = "bundled" + """The caller has bundled all dependencies into the uploaded zip; the service performs no remote + build.""" + REMOTE_BUILD = "remote_build" + """The service builds dependencies remotely from the manifest included in the uploaded zip.""" + + class ComputerEnvironment(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of ComputerEnvironment.""" @@ -329,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.""" @@ -364,6 +435,17 @@ class DeploymentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Model deployment.""" +class EvalRunOutputItemResultStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The evaluation status for an evaluation run output item result.""" + + COMPLETED = "completed" + """The evaluator completed successfully for this result item.""" + ERRORED = "errored" + """The evaluator encountered an error for this result item.""" + SKIPPED = "skipped" + """The evaluator skipped this result item.""" + + class EvaluationRuleActionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of the evaluation action.""" @@ -415,6 +497,22 @@ class EvaluatorDefinitionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Service-based evaluator.""" OPENAI_GRADERS = "openai_graders" """OpenAI graders.""" + RUBRIC = "rubric" + """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.""" + + +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): @@ -450,6 +548,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.""" @@ -525,6 +678,21 @@ class IsolationKeySourceKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """HEADER.""" +class JobStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Extensible status values shared by Foundry jobs.""" + + QUEUED = "queued" + """Job is waiting to start.""" + IN_PROGRESS = "in_progress" + """Job is actively processing.""" + SUCCEEDED = "succeeded" + """Job completed successfully.""" + FAILED = "failed" + """Job failed.""" + CANCELLED = "cancelled" + """Job was cancelled by the caller.""" + + class MemoryItemKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Memory item kind.""" @@ -532,6 +700,8 @@ class MemoryItemKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """User profile information extracted from conversations.""" CHAT_SUMMARY = "chat_summary" """Summary of chat conversations.""" + PROCEDURAL = "procedural" + """Routine procedures extracted from conversations.""" class MemoryOperationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -561,6 +731,8 @@ class MemoryStoreObjectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """MEMORY_STORE_DELETED.""" MEMORY_STORE_SCOPE_DELETED = "memory_store.scope.deleted" """MEMORY_STORE_SCOPE_DELETED.""" + MEMORY_DELETED = "memory_store.item.deleted" + """MEMORY_DELETED.""" class MemoryStoreUpdateStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -609,6 +781,24 @@ class OperationState(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The operation has been canceled by the user.""" +class OptimizationMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Run mode for an optimization job.""" + + OPTIMIZE = "optimize" + """Full optimization: baseline + mutation strategies.""" + + +class OptimizationStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Optimization strategy dimension.""" + + INSTRUCTION = "instruction" + """Instruction-tuning strategy — rewrites agent system prompts.""" + MODEL = "model" + """Model-selection strategy — evaluates alternative LLM deployments.""" + SKILL = "skill" + """Skill-tuning strategy — generates or modifies agent tool descriptions.""" + + class PageOrder(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of PageOrder.""" @@ -624,7 +814,10 @@ class PendingUploadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): NONE = "None" """No pending upload.""" BLOB_REFERENCE = "BlobReference" - """Blob Reference is the only supported type.""" + """Deprecated: the service never read this value and silently ignored it. Use + TemporaryBlobReference instead.""" + TEMPORARY_BLOB_REFERENCE = "TemporaryBlobReference" + """Temporary blob reference.""" class RankerVersionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -674,6 +867,63 @@ class RiskCategory(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents content that involves task adherence.""" +class RoutineActionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The discriminator values supported for routine actions.""" + + INVOKE_AGENT_RESPONSES_API = "invoke_agent_responses_api" + """Dispatches through the responses API.""" + INVOKE_AGENT_INVOCATIONS_API = "invoke_agent_invocations_api" + """Dispatches through the raw invocations API.""" + + +class RoutineAttemptSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Known source paths that can produce a routine run.""" + + EVENT_FIRE = "event_fire" + """A dispatch fired from an event delivery.""" + MANUAL_DISPATCH = "manual_dispatch" + """A dispatch executed synchronously by a direct request.""" + QUEUED_DISPATCH = "queued_dispatch" + """A dispatch executed asynchronously from the dispatch queue.""" + SCHEDULE_DELIVERY = "schedule_delivery" + """A dispatch fired from a schedule delivery.""" + TIMER_DELIVERY = "timer_delivery" + """A dispatch fired from a timer delivery.""" + + +class RoutineDispatchPayloadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The discriminator values supported for manual routine dispatch payloads.""" + + INVOKE_AGENT_RESPONSES_API = "invoke_agent_responses_api" + """A manual payload for a responses API routine dispatch.""" + INVOKE_AGENT_INVOCATIONS_API = "invoke_agent_invocations_api" + """A manual payload for an invocations API routine dispatch.""" + + +class RoutineRunPhase(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Known lifecycle phases recorded for a routine run.""" + + QUEUED = "queued" + """The run is queued for dispatch.""" + DISPATCHING = "dispatching" + """The run is currently being dispatched.""" + COMPLETED = "completed" + """The run finished successfully.""" + FAILED = "failed" + """The run finished with an error.""" + + +class RoutineTriggerType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The discriminator values supported for routine triggers.""" + + GITHUB_ISSUE_OPENED = "github_issue_opened" + """A GitHub issue-opened trigger.""" + SCHEDULE = "schedule" + """A recurring cron-based trigger.""" + TIMER = "timer" + """A one-shot timer trigger.""" + + class SampleType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The type of sample used in the analysis.""" @@ -725,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.""" @@ -840,6 +1099,10 @@ class ToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """MEMORY_SEARCH_PREVIEW.""" WORK_IQ_PREVIEW = "work_iq_preview" """WORK_IQ_PREVIEW.""" + FABRIC_IQ_PREVIEW = "fabric_iq_preview" + """FABRIC_IQ_PREVIEW.""" + TOOLBOX_SEARCH_PREVIEW = "toolbox_search_preview" + """TOOLBOX_SEARCH_PREVIEW.""" AZURE_AI_SEARCH = "azure_ai_search" """AZURE_AI_SEARCH.""" AZURE_FUNCTION = "azure_function" 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 f2da2ee9bdb2..f904d16f9caa 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 @@ -12,6 +12,7 @@ from typing import Any, Literal, Mapping, Optional, TYPE_CHECKING, Union, overload from .._utils.model_base import Model as _Model, rest_discriminator, rest_field +from .._utils.utils import FileType from ._enums import ( AgentBlueprintReferenceType, AgentEndpointAuthorizationSchemeType, @@ -21,11 +22,15 @@ ContainerSkillType, CredentialType, CustomToolParamFormatType, + DataGenerationJobOutputType, + DataGenerationJobSourceType, + DataGenerationJobType, DatasetType, DeploymentType, EvaluationRuleActionType, EvaluationTaxonomyInputType, EvaluatorDefinitionType, + EvaluatorGenerationJobSourceType, FunctionShellToolParamEnvironmentType, IndexType, InsightType, @@ -36,6 +41,9 @@ OpenApiAuthType, PendingUploadType, RecurrenceType, + RoutineActionType, + RoutineDispatchPayloadType, + RoutineTriggerType, SampleType, ScheduleTaskType, TelemetryEndpointAuthType, @@ -59,16 +67,18 @@ class Tool(_Model): A2APreviewTool, ApplyPatchToolParam, AzureAISearchTool, AzureFunctionTool, BingCustomSearchPreviewTool, BingGroundingTool, BrowserAutomationPreviewTool, CaptureStructuredOutputsTool, CodeInterpreterTool, ComputerUsePreviewTool, CustomToolParam, - MicrosoftFabricPreviewTool, FileSearchTool, FunctionTool, ImageGenTool, LocalShellToolParam, - MCPTool, MemorySearchPreviewTool, OpenApiTool, SharepointPreviewTool, FunctionShellToolParam, - WebSearchTool, WebSearchPreviewTool, WorkIQPreviewTool + MicrosoftFabricPreviewTool, FabricIQPreviewTool, FileSearchTool, FunctionTool, ImageGenTool, + LocalShellToolParam, MCPTool, MemorySearchPreviewTool, OpenApiTool, SharepointPreviewTool, + FunctionShellToolParam, ToolboxSearchPreviewTool, WebSearchTool, WebSearchPreviewTool, + WorkIQPreviewTool :ivar type: Required. Known values are: "function", "file_search", "computer_use_preview", "web_search", "mcp", "code_interpreter", "image_generation", "local_shell", "shell", "custom", "web_search_preview", "apply_patch", "a2a_preview", "bing_custom_search_preview", "browser_automation_preview", "fabric_dataagent_preview", "sharepoint_grounding_preview", - "memory_search_preview", "work_iq_preview", "azure_ai_search", "azure_function", - "bing_grounding", "capture_structured_outputs", and "openapi". + "memory_search_preview", "work_iq_preview", "fabric_iq_preview", "toolbox_search_preview", + "azure_ai_search", "azure_function", "bing_grounding", "capture_structured_outputs", and + "openapi". :vartype type: str or ~azure.ai.projects.models.ToolType """ @@ -79,8 +89,8 @@ class Tool(_Model): \"shell\", \"custom\", \"web_search_preview\", \"apply_patch\", \"a2a_preview\", \"bing_custom_search_preview\", \"browser_automation_preview\", \"fabric_dataagent_preview\", \"sharepoint_grounding_preview\", \"memory_search_preview\", \"work_iq_preview\", - \"azure_ai_search\", \"azure_function\", \"bing_grounding\", \"capture_structured_outputs\", - and \"openapi\".""" + \"fabric_iq_preview\", \"toolbox_search_preview\", \"azure_ai_search\", \"azure_function\", + \"bing_grounding\", \"capture_structured_outputs\", and \"openapi\".""" @overload def __init__( @@ -105,6 +115,14 @@ class A2APreviewTool(Tool, discriminator="a2a_preview"): :ivar type: The type of the tool. Always ``"a2a_preview``. Required. A2A_PREVIEW. :vartype type: str or ~azure.ai.projects.models.A2A_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar base_url: Base URL of the agent. :vartype base_url: str :ivar agent_card_path: The path to the agent card relative to the ``base_url``. If not @@ -118,6 +136,16 @@ class A2APreviewTool(Tool, discriminator="a2a_preview"): type: Literal[ToolType.A2A_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The type of the tool. Always ``\"a2a_preview``. Required. A2A_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" base_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Base URL of the agent.""" agent_card_path: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -131,6 +159,9 @@ class A2APreviewTool(Tool, discriminator="a2a_preview"): def __init__( self, *, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, base_url: Optional[str] = None, agent_card_path: Optional[str] = None, project_connection_id: Optional[str] = None, @@ -410,13 +441,101 @@ 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. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - HostedAgentDefinition, PromptAgentDefinition, WorkflowAgentDefinition + ExternalAgentDefinition, HostedAgentDefinition, PromptAgentDefinition, WorkflowAgentDefinition - :ivar kind: Required. Known values are: "prompt", "hosted", and "workflow". + :ivar kind: Required. Known values are: "prompt", "hosted", "workflow", and "external". :vartype kind: str or ~azure.ai.projects.models.AgentKind :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. :vartype rai_config: ~azure.ai.projects.models.RaiConfig @@ -424,7 +543,7 @@ class AgentDefinition(_Model): __mapping__: dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"prompt\", \"hosted\", and \"workflow\".""" + """Required. Known values are: \"prompt\", \"hosted\", \"workflow\", and \"external\".""" rai_config: Optional["_models.RaiConfig"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Configuration for Responsible AI (RAI) content filtering and safety features.""" @@ -459,7 +578,7 @@ class AgentDetails(_Model): :ivar versions: The latest version of the agent. Required. :vartype versions: ~azure.ai.projects.models.AgentObjectVersions :ivar agent_endpoint: The endpoint configuration for the agent. - :vartype agent_endpoint: ~azure.ai.projects.models.AgentEndpoint + :vartype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig :ivar instance_identity: The instance identity of the agent. :vartype instance_identity: ~azure.ai.projects.models.AgentIdentity :ivar blueprint: The blueprint for the agent. @@ -478,7 +597,7 @@ class AgentDetails(_Model): """The name of the agent. Required.""" versions: "_models.AgentObjectVersions" = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The latest version of the agent. Required.""" - agent_endpoint: Optional["_models.AgentEndpoint"] = rest_field( + agent_endpoint: Optional["_models.AgentEndpointConfig"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) """The endpoint configuration for the agent.""" @@ -498,7 +617,7 @@ def __init__( id: str, # pylint: disable=redefined-builtin name: str, versions: "_models.AgentObjectVersions", - agent_endpoint: Optional["_models.AgentEndpoint"] = None, + agent_endpoint: Optional["_models.AgentEndpointConfig"] = None, agent_card: Optional["_models.AgentCard"] = None, ) -> None: ... @@ -513,8 +632,40 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AgentEndpoint(_Model): - """AgentEndpoint. +class AgentEndpointAuthorizationScheme(_Model): + """AgentEndpointAuthorizationScheme. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + BotServiceAuthorizationScheme, BotServiceRbacAuthorizationScheme, EntraAuthorizationScheme + + :ivar type: Required. Known values are: "Entra", "BotService", and "BotServiceRbac". + :vartype type: str or ~azure.ai.projects.models.AgentEndpointAuthorizationSchemeType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"Entra\", \"BotService\", and \"BotServiceRbac\".""" + + @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 AgentEndpointConfig(_Model): + """AgentEndpointConfig. :ivar version_selector: The version selector of the agent endpoint determines how traffic is routed to different versions of the agent. @@ -560,19 +711,22 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AgentEndpointAuthorizationScheme(_Model): - """AgentEndpointAuthorizationScheme. +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: - BotServiceAuthorizationScheme, BotServiceRbacAuthorizationScheme, EntraAuthorizationScheme + AgentEvaluatorGenerationJobSource, DatasetEvaluatorGenerationJobSource, + PromptEvaluatorGenerationJobSource, TracesEvaluatorGenerationJobSource - :ivar type: Required. Known values are: "Entra", "BotService", and "BotServiceRbac". - :vartype type: str or ~azure.ai.projects.models.AgentEndpointAuthorizationSchemeType + :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"]) - """Required. Known values are: \"Entra\", \"BotService\", and \"BotServiceRbac\".""" + """The type of source. Required. Known values are: \"prompt\", \"agent\", \"traces\", and + \"dataset\".""" @overload def __init__( @@ -592,6 +746,55 @@ 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. @@ -776,6 +979,51 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class AgentsPagedResultOptimizationCandidate(_Model): + """The response data for a requested list of items. + + :ivar data: The requested list of items. Required. + :vartype data: list[~azure.ai.projects.models.OptimizationCandidate] + :ivar first_id: The first ID represented in this list. + :vartype first_id: str + :ivar last_id: The last ID represented in this list. + :vartype last_id: str + :ivar has_more: A value indicating whether there are additional values available not captured + in this list. Required. + :vartype has_more: bool + """ + + data: list["_models.OptimizationCandidate"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The requested list of items. Required.""" + first_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The first ID represented in this list.""" + last_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The last ID represented in this list.""" + has_more: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A value indicating whether there are additional values available not captured in this list. + Required.""" + + @overload + def __init__( + self, + *, + data: list["_models.OptimizationCandidate"], + has_more: bool, + first_id: Optional[str] = None, + last_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 EvaluationTaxonomyInput(_Model): """Input configuration for the evaluation taxonomy. @@ -815,14 +1063,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"] @@ -833,7 +1081,7 @@ class AgentTaxonomyInput(EvaluationTaxonomyInput, discriminator="agent"): def __init__( self, *, - target: "_models.Target", + target: "_models.EvaluationTarget", risk_categories: list[Union[str, "_models.RiskCategory"]], ) -> None: ... @@ -1204,6 +1452,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. @@ -1250,7 +1537,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: @@ -1282,7 +1569,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 @@ -1295,6 +1582,8 @@ class AzureAIAgentTarget(Target, discriminator="azure_ai_agent"): :ivar tool_descriptions: The parameters used to control the sampling behavior of the agent during text generation. :vartype tool_descriptions: list[~azure.ai.projects.models.ToolDescription] + :ivar tools: + :vartype tools: list[~azure.ai.projects.models.Tool] """ type: Literal["azure_ai_agent"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore @@ -1307,6 +1596,7 @@ class AzureAIAgentTarget(Target, discriminator="azure_ai_agent"): visibility=["read", "create", "update", "delete", "query"] ) """The parameters used to control the sampling behavior of the agent during text generation.""" + tools: Optional[list["_models.Tool"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( @@ -1315,6 +1605,7 @@ def __init__( name: str, version: Optional[str] = None, tool_descriptions: Optional[list["_models.ToolDescription"]] = None, + tools: Optional[list["_models.Tool"]] = None, ) -> None: ... @overload @@ -1329,7 +1620,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 @@ -1487,12 +1778,30 @@ class AzureAISearchTool(Tool, discriminator="azure_ai_search"): :ivar type: The object type, which is always 'azure_ai_search'. Required. AZURE_AI_SEARCH. :vartype type: str or ~azure.ai.projects.models.AZURE_AI_SEARCH + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar azure_ai_search: The azure ai search index resource. Required. :vartype azure_ai_search: ~azure.ai.projects.models.AzureAISearchToolResource """ type: Literal[ToolType.AZURE_AI_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The object type, which is always 'azure_ai_search'. Required. AZURE_AI_SEARCH.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" azure_ai_search: "_models.AzureAISearchToolResource" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -1503,6 +1812,9 @@ def __init__( self, *, azure_ai_search: "_models.AzureAISearchToolResource", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -1716,6 +2028,10 @@ class AzureFunctionTool(Tool, discriminator="azure_function"): :vartype type: str or ~azure.ai.projects.models.AZURE_FUNCTION :ivar azure_function: The Azure Function Tool definition. Required. :vartype azure_function: ~azure.ai.projects.models.AzureFunctionDefinition + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] """ type: Literal[ToolType.AZURE_FUNCTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore @@ -1724,12 +2040,19 @@ class AzureFunctionTool(Tool, discriminator="azure_function"): visibility=["read", "create", "update", "delete", "query"] ) """The Azure Function Tool definition. Required.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" @overload def __init__( self, *, azure_function: "_models.AzureFunctionDefinition", + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -1744,7 +2067,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: @@ -1776,7 +2099,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. @@ -1876,6 +2199,14 @@ class BingCustomSearchPreviewTool(Tool, discriminator="bing_custom_search_previe :ivar type: The object type, which is always 'bing_custom_search_preview'. Required. BING_CUSTOM_SEARCH_PREVIEW. :vartype type: str or ~azure.ai.projects.models.BING_CUSTOM_SEARCH_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar bing_custom_search_preview: The bing custom search tool parameters. Required. :vartype bing_custom_search_preview: ~azure.ai.projects.models.BingCustomSearchToolParameters """ @@ -1883,6 +2214,16 @@ class BingCustomSearchPreviewTool(Tool, discriminator="bing_custom_search_previe type: Literal[ToolType.BING_CUSTOM_SEARCH_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The object type, which is always 'bing_custom_search_preview'. Required. BING_CUSTOM_SEARCH_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" bing_custom_search_preview: "_models.BingCustomSearchToolParameters" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -1893,6 +2234,9 @@ def __init__( self, *, bing_custom_search_preview: "_models.BingCustomSearchToolParameters", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -2028,12 +2372,30 @@ class BingGroundingTool(Tool, discriminator="bing_grounding"): :ivar type: The object type, which is always 'bing_grounding'. Required. BING_GROUNDING. :vartype type: str or ~azure.ai.projects.models.BING_GROUNDING + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar bing_grounding: The bing grounding search tool parameters. Required. :vartype bing_grounding: ~azure.ai.projects.models.BingGroundingSearchToolParameters """ type: Literal[ToolType.BING_GROUNDING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The object type, which is always 'bing_grounding'. Required. BING_GROUNDING.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" bing_grounding: "_models.BingGroundingSearchToolParameters" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -2044,6 +2406,9 @@ def __init__( self, *, bing_grounding: "_models.BingGroundingSearchToolParameters", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -2181,6 +2546,14 @@ class BrowserAutomationPreviewTool(Tool, discriminator="browser_automation_previ :ivar type: The object type, which is always 'browser_automation_preview'. Required. BROWSER_AUTOMATION_PREVIEW. :vartype type: str or ~azure.ai.projects.models.BROWSER_AUTOMATION_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar browser_automation_preview: The Browser Automation Tool parameters. Required. :vartype browser_automation_preview: ~azure.ai.projects.models.BrowserAutomationToolParameters """ @@ -2188,6 +2561,16 @@ class BrowserAutomationPreviewTool(Tool, discriminator="browser_automation_previ type: Literal[ToolType.BROWSER_AUTOMATION_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The object type, which is always 'browser_automation_preview'. Required. BROWSER_AUTOMATION_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" browser_automation_preview: "_models.BrowserAutomationToolParameters" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -2198,6 +2581,9 @@ def __init__( self, *, browser_automation_preview: "_models.BrowserAutomationToolParameters", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -2272,29 +2658,120 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CaptureStructuredOutputsTool(Tool, discriminator="capture_structured_outputs"): - """A tool for capturing structured outputs. +class CandidateDeployConfig(_Model): + """Deploy-config blob for a candidate. Suitable for setting OPTIMIZATION_CONFIG on a hosted-agent + version. - :ivar type: The type of the tool. Always ``capture_structured_outputs``. Required. - CAPTURE_STRUCTURED_OUTPUTS. - :vartype type: str or ~azure.ai.projects.models.CAPTURE_STRUCTURED_OUTPUTS - :ivar name: Optional user-defined name for this tool or configuration. - :vartype name: str - :ivar description: Optional user-defined description for this tool or configuration. - :vartype description: str - :ivar outputs: The structured outputs to capture from the model. Required. - :vartype outputs: ~azure.ai.projects.models.StructuredOutputDefinition + :ivar instructions: System prompt / instructions. + :vartype instructions: str + :ivar model: Foundry deployment name. + :vartype model: str + :ivar temperature: Optional sampling temperature. + :vartype temperature: float + :ivar skills: Optional skill overrides. + :vartype skills: list[~azure.ai.projects.models.OptimizationAgentSkill] """ - type: Literal[ToolType.CAPTURE_STRUCTURED_OUTPUTS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``capture_structured_outputs``. Required. - CAPTURE_STRUCTURED_OUTPUTS.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined name for this tool or configuration.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined description for this tool or configuration.""" - outputs: "_models.StructuredOutputDefinition" = rest_field( - visibility=["read", "create", "update", "delete", "query"] + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """System prompt / instructions.""" + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Foundry deployment name.""" + temperature: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional sampling temperature.""" + skills: Optional[list["_models.OptimizationAgentSkill"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional skill overrides.""" + + @overload + def __init__( + self, + *, + instructions: Optional[str] = None, + model: Optional[str] = None, + temperature: Optional[float] = None, + skills: Optional[list["_models.OptimizationAgentSkill"]] = 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 CandidateResults(_Model): + """Full per-task evaluation results for a candidate, returned by GET /candidates/{id}/results. + + :ivar candidate_id: Owning candidate id. Required. + :vartype candidate_id: str + :ivar results: Per-task evaluation rows. Required. + :vartype results: list[~azure.ai.projects.models.OptimizationTaskResult] + """ + + candidate_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Owning candidate id. Required.""" + results: list["_models.OptimizationTaskResult"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-task evaluation rows. Required.""" + + @overload + def __init__( + self, + *, + candidate_id: str, + results: list["_models.OptimizationTaskResult"], + ) -> 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 CaptureStructuredOutputsTool(Tool, discriminator="capture_structured_outputs"): + """A tool for capturing structured outputs. + + :ivar type: The type of the tool. Always ``capture_structured_outputs``. Required. + CAPTURE_STRUCTURED_OUTPUTS. + :vartype type: str or ~azure.ai.projects.models.CAPTURE_STRUCTURED_OUTPUTS + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + :ivar outputs: The structured outputs to capture from the model. Required. + :vartype outputs: ~azure.ai.projects.models.StructuredOutputDefinition + """ + + type: Literal[ToolType.CAPTURE_STRUCTURED_OUTPUTS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``capture_structured_outputs``. Required. + CAPTURE_STRUCTURED_OUTPUTS.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + outputs: "_models.StructuredOutputDefinition" = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) """The structured outputs to capture from the model. Required.""" @@ -2305,6 +2782,7 @@ def __init__( outputs: "_models.StructuredOutputDefinition", name: Optional[str] = None, description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -2361,7 +2839,7 @@ class MemoryItem(_Model): """A single memory item stored in the memory store, containing content and metadata. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ChatSummaryMemoryItem, UserProfileMemoryItem + ChatSummaryMemoryItem, ProceduralMemoryItem, UserProfileMemoryItem :ivar memory_id: The unique ID of the memory item. Required. :vartype memory_id: str @@ -2372,8 +2850,8 @@ class MemoryItem(_Model): :vartype scope: str :ivar content: The content of the memory. Required. :vartype content: str - :ivar kind: The kind of the memory item. Required. Known values are: "user_profile" and - "chat_summary". + :ivar kind: The kind of the memory item. Required. Known values are: "user_profile", + "chat_summary", and "procedural". :vartype kind: str or ~azure.ai.projects.models.MemoryItemKind """ @@ -2389,7 +2867,8 @@ class MemoryItem(_Model): content: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The content of the memory. Required.""" kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) - """The kind of the memory item. Required. Known values are: \"user_profile\" and \"chat_summary\".""" + """The kind of the memory item. Required. Known values are: \"user_profile\", \"chat_summary\", + and \"procedural\".""" @overload def __init__( @@ -2579,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", and "openai_graders". + "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. @@ -2597,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\", and \"openai_graders\".""" + \"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.""" @@ -2699,6 +3178,16 @@ class CodeConfiguration(_Model): :vartype runtime: str :ivar entry_point: The entry point command and arguments for the code execution. Required. :vartype entry_point: list[str] + :ivar dependency_resolution: How package dependencies are resolved at deployment time. Defaults + to ``bundled``, where the caller bundles all dependencies into the uploaded zip and the service + performs no remote build. ``remote_build`` instructs the service to build dependencies remotely + from the manifest included in the uploaded zip. Required. Known values are: "bundled" and + "remote_build". + :vartype dependency_resolution: str or ~azure.ai.projects.models.CodeDependencyResolution + :ivar content_hash: The SHA-256 hex digest of the uploaded code zip. Set by the service from + the ``x-ms-code-zip-sha256`` request header; read-only in responses and never accepted in + request payloads. + :vartype content_hash: str """ runtime: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -2706,6 +3195,17 @@ class CodeConfiguration(_Model): Required.""" entry_point: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The entry point command and arguments for the code execution. Required.""" + dependency_resolution: Union[str, "_models.CodeDependencyResolution"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """How package dependencies are resolved at deployment time. Defaults to ``bundled``, where the + caller bundles all dependencies into the uploaded zip and the service performs no remote build. + ``remote_build`` instructs the service to build dependencies remotely from the manifest + included in the uploaded zip. Required. Known values are: \"bundled\" and \"remote_build\".""" + content_hash: Optional[str] = rest_field(visibility=["read"]) + """The SHA-256 hex digest of the uploaded code zip. Set by the service from the + ``x-ms-code-zip-sha256`` request header; read-only in responses and never accepted in request + payloads.""" @overload def __init__( @@ -2713,6 +3213,7 @@ def __init__( *, runtime: str, entry_point: list[str], + dependency_resolution: Union[str, "_models.CodeDependencyResolution"], ) -> None: ... @overload @@ -2736,6 +3237,10 @@ class CodeInterpreterTool(Tool, discriminator="code_interpreter"): :vartype name: str :ivar description: Optional user-defined description for this tool or configuration. :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar container: The code interpreter container. Can be a container ID or an object that specifies uploaded file IDs to make available to your code, along with an optional ``memory_limit`` setting. If not provided, the service assumes auto. Is either a str type or a @@ -2749,6 +3254,12 @@ class CodeInterpreterTool(Tool, discriminator="code_interpreter"): """Optional user-defined name for this tool or configuration.""" description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" container: Optional[Union[str, "_models.AutoCodeInterpreterToolParam"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -2763,6 +3274,7 @@ def __init__( *, name: Optional[str] = None, description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, container: Optional[Union[str, "_models.AutoCodeInterpreterToolParam"]] = None, ) -> None: ... @@ -3398,6 +3910,133 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = IndexType.COSMOS_DB # type: ignore +class CreateAgentVersionFromCodeContent(_Model): + """Multipart request body for updating or versioning a code-based agent (POST /agents/{name} and + POST /agents/{name}/versions). + + :ivar metadata: JSON metadata including description and hosted definition. Required. + :vartype metadata: ~azure.ai.projects.models.CreateAgentVersionFromCodeMetadata + :ivar code: The code zip file (max 250 MB). Required. + :vartype code: ~azure.ai.projects._utils.utils.FileType + """ + + metadata: "_models.CreateAgentVersionFromCodeMetadata" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """JSON metadata including description and hosted definition. Required.""" + code: FileType = rest_field( + visibility=["read", "create", "update", "delete", "query"], is_multipart_file_input=True + ) + """The code zip file (max 250 MB). Required.""" + + @overload + def __init__( + self, + *, + metadata: "_models.CreateAgentVersionFromCodeMetadata", + code: FileType, + ) -> 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 CreateAgentVersionFromCodeMetadata(_Model): + """JSON metadata for code-based agent operations (create, update, create version). The agent name + comes from the URL path parameter or the ``x-ms-agent-name`` header, so it is not included in + this model. The content hash (SHA-256 of the zip) is carried in the ``x-ms-code-zip-sha256`` + header. + + :ivar description: A human-readable description of the agent. + :vartype description: str + :ivar 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. + :vartype metadata: dict[str, str] + :ivar definition: The hosted agent definition including code_configuration (runtime, + entry_point), cpu, memory, and protocol_versions. Required. + :vartype definition: ~azure.ai.projects.models.HostedAgentDefinition + """ + + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the agent.""" + metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """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.""" + definition: "_models.HostedAgentDefinition" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The hosted agent definition including code_configuration (runtime, entry_point), cpu, memory, + and protocol_versions. Required.""" + + @overload + def __init__( + self, + *, + definition: "_models.HostedAgentDefinition", + description: Optional[str] = None, + metadata: 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 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. @@ -3438,7 +4077,7 @@ class CronTrigger(Trigger, discriminator="Cron"): :vartype type: str or ~azure.ai.projects.models.CRON :ivar expression: Cron expression that defines the schedule frequency. Required. :vartype expression: str - :ivar time_zone: Time zone for the cron schedule. + :ivar time_zone: Time zone for the cron schedule. Defaults to ``UTC``. :vartype time_zone: str :ivar start_time: Start time for the cron schedule in ISO 8601 format. :vartype start_time: ~datetime.datetime @@ -3451,7 +4090,7 @@ class CronTrigger(Trigger, discriminator="Cron"): expression: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Cron expression that defines the schedule frequency. Required.""" time_zone: Optional[str] = rest_field(name="timeZone", visibility=["read", "create", "update", "delete", "query"]) - """Time zone for the cron schedule.""" + """Time zone for the cron schedule. Defaults to ``UTC``.""" start_time: Optional[datetime.datetime] = rest_field( name="startTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" ) @@ -3724,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 @@ -3754,67 +4423,53 @@ 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 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 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 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 """ - __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.""" + 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\".""" + 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__( self, *, - data_uri: str, - type: str, - connection_name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + name: str, + sources: list["_models.DataGenerationJobSource"], + options: "_models.DataGenerationJobOptions", + scenario: Union[str, "_models.DataGenerationJobScenario"], + output_options: Optional["_models.DataGenerationJobOutputOptions"] = None, ) -> None: ... @overload @@ -3828,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 @@ -3868,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 @@ -3913,33 +4569,37 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteMemoryStoreResult(_Model): - """DeleteMemoryStoreResult. +class DataGenerationJobOutputOptions(_Model): + """Output options for 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. + :ivar name: Name to assign to the output. Used as the filename for Azure OpenAI file outputs + (fine-tuning scenarios) and as the dataset name for dataset outputs (evaluation scenario). :vartype name: str - :ivar deleted: Whether the memory store was successfully deleted. Required. - :vartype deleted: bool + :ivar description: Description to assign to the output. Applies only to dataset outputs + (evaluation scenario); ignored for Azure OpenAI file outputs. + :vartype description: str + :ivar tags: Tags to assign to the output. Applies only to dataset outputs (evaluation + scenario); ignored for Azure OpenAI file outputs. + :vartype tags: dict[str, str] """ - 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 memory store. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the memory store was successfully deleted. Required.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name to assign to the output. Used as the filename for Azure OpenAI file outputs (fine-tuning + scenarios) and as the dataset name for dataset outputs (evaluation scenario).""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description to assign to the output. Applies only to dataset outputs (evaluation scenario); + ignored for Azure OpenAI file outputs.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Tags to assign to the output. Applies only to dataset outputs (evaluation scenario); ignored + for Azure OpenAI file outputs.""" @overload def __init__( self, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED], - name: str, - deleted: bool, + name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -3953,26 +4613,36 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteSkillResponse(_Model): - """A deleted skill Object. +class DataGenerationJobResult(_Model): + """Result produced by a successful data generation job. - :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 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 """ - 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.""" + 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( + visibility=["read", "create", "update", "delete", "query"] + ) + """The token usage information for the data generation job.""" @overload def __init__( self, *, - name: str, - deleted: bool, + generated_samples: int, + outputs: Optional[list["_models.DataGenerationJobOutput"]] = None, + token_usage: Optional["_models.DataGenerationTokenUsage"] = None, ) -> None: ... @overload @@ -3986,29 +4656,21 @@ 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 DataGenerationModelOptions(_Model): + """LLM model options for data generation jobs. - :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 model: Base model name used to generate data. Required. + :vartype model: str """ - __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.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base model name used to generate data. Required.""" @overload def __init__( self, *, - type: str, + model: str, ) -> None: ... @overload @@ -4022,28 +4684,42 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EmbeddingConfiguration(_Model): - """Embedding configuration class. +class DataGenerationTokenUsage(_Model): + """Token usage information for a data generation job. - :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 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 """ - 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.""" + 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.""" + + +class DatasetCredential(_Model): + """Represents a reference to a blob for consumption. + + :ivar blob_reference: Credential info to access the storage account. Required. + :vartype blob_reference: ~azure.ai.projects.models.BlobReference + """ + + 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 @@ -4057,27 +4733,39 @@ 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: Required. ENTRA. - :vartype type: str or ~azure.ai.projects.models.ENTRA - :ivar isolation_key_source: Required. - :vartype isolation_key_source: ~azure.ai.projects.models.IsolationKeySource + :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. + :vartype name: str + :ivar version: The version of the output dataset. + :vartype version: str + :ivar description: Description of the output dataset. + :vartype description: str + :ivar tags: Tag dictionary of the output dataset. + :vartype tags: dict[str, str] """ - type: Literal[AgentEndpointAuthorizationSchemeType.ENTRA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. ENTRA.""" - isolation_key_source: "_models.IsolationKeySource" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Required.""" + 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"]) + """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"]) + """Description of the output dataset.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read"]) + """Tag dictionary of the output dataset.""" @overload def __init__( self, - *, - isolation_key_source: "_models.IsolationKeySource", ) -> None: ... @overload @@ -4089,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 @@ -4116,28 +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 IsolationKeySource(_Model): - """IsolationKeySource. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - EntraIsolationKeySource, HeaderIsolationKeySource +class DatasetEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="dataset"): + """Dataset source for evaluator generation jobs — reference to a dataset. - :ivar kind: Required. Known values are: "Entra" and "Header". - :vartype kind: str or ~azure.ai.projects.models.IsolationKeySourceKind + :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 """ - __mapping__: dict[str, _Model] = {} - kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"Entra\" and \"Header\".""" + 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 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, *, - kind: str, + name: str, + description: Optional[str] = None, + version: Optional[str] = None, ) -> None: ... @overload @@ -4149,21 +4870,59 @@ 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 -class EntraIsolationKeySource(IsolationKeySource, discriminator="Entra"): - """EntraIsolationKeySource. +class DatasetItem(_Model): + """A single evaluation task with input query, expected output, and evaluation criteria. - :ivar kind: Required. ENTRA. - :vartype kind: str or ~azure.ai.projects.models.ENTRA + :ivar name: Unique-within-the-dataset identifier for this task. Required. + :vartype name: str + :ivar query: The user query / input for the task. Required. + :vartype query: str + :ivar ground_truth: Optional ground truth used by reference-based evaluators. + :vartype ground_truth: str + :ivar criteria: Per-task evaluation criteria. Defaults to the job-level evaluators if unset. + :vartype criteria: list[~azure.ai.projects.models.EvaluationCriterion] + :ivar eval_results: Pre-computed evaluation results in AOAI-compatible format. When provided + together with ``response_items``, the baseline run-and-evaluate phase is skipped. + :vartype eval_results: list[~azure.ai.projects.models.EvalRunOutputItemResult] + :ivar response_items: Pre-computed agent response output items. Captures the full trajectory + (function calls, tool outputs, messages) from a prior agent run. + :vartype response_items: list[dict[str, any]] """ - kind: Literal[IsolationKeySourceKind.ENTRA] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. ENTRA.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Unique-within-the-dataset identifier for this task. Required.""" + query: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The user query / input for the task. Required.""" + ground_truth: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional ground truth used by reference-based evaluators.""" + criteria: Optional[list["_models.EvaluationCriterion"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-task evaluation criteria. Defaults to the job-level evaluators if unset.""" + eval_results: Optional[list["_models.EvalRunOutputItemResult"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Pre-computed evaluation results in AOAI-compatible format. When provided together with + ``response_items``, the baseline run-and-evaluate phase is skipped.""" + response_items: Optional[list[dict[str, Any]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Pre-computed agent response output items. Captures the full trajectory (function calls, tool + outputs, messages) from a prior agent run.""" @overload def __init__( self, + *, + name: str, + query: str, + ground_truth: Optional[str] = None, + criteria: Optional[list["_models.EvaluationCriterion"]] = None, + eval_results: Optional[list["_models.EvalRunOutputItemResult"]] = None, + response_items: Optional[list[dict[str, Any]]] = None, ) -> None: ... @overload @@ -4175,39 +4934,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = IsolationKeySourceKind.ENTRA # type: ignore -class EvalResult(_Model): - """Result of the evaluation. +class DatasetRef(_Model): + """Reference to a registered dataset in the Foundry Dataset Service. - :ivar name: name of the check. Required. + :ivar name: Dataset name. Required. :vartype name: str - :ivar type: type of the check. Required. - :vartype type: str - :ivar score: score. Required. - :vartype score: float - :ivar passed: indicates if the check passed or failed. Required. - :vartype passed: bool + :ivar version: Dataset version. If not specified, the latest version is used. + :vartype version: str """ name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """name of the check. Required.""" - type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """type of the check. Required.""" - score: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """score. Required.""" - passed: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """indicates if the check passed or failed. Required.""" + """Dataset name. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Dataset version. If not specified, the latest version is used.""" @overload def __init__( self, *, name: str, - type: str, - score: float, - passed: bool, + version: Optional[str] = None, ) -> None: ... @overload @@ -4221,49 +4969,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalRunResultCompareItem(_Model): - """Metric comparison for a treatment against the baseline. +class DatasetReference(_Model): + """Reference to a versioned Foundry Dataset. - :ivar treatment_run_id: The treatment run ID. Required. - :vartype treatment_run_id: str - :ivar treatment_run_summary: Summary statistics of the treatment run. Required. - :vartype treatment_run_summary: ~azure.ai.projects.models.EvalRunResultSummary - :ivar delta_estimate: Estimated difference between treatment and baseline. Required. - :vartype delta_estimate: float - :ivar p_value: P-value for the treatment effect. Required. - :vartype p_value: float - :ivar treatment_effect: Type of treatment effect. Required. Known values are: "TooFewSamples", - "Inconclusive", "Changed", "Improved", and "Degraded". - :vartype treatment_effect: str or ~azure.ai.projects.models.TreatmentEffectType + :ivar name: Dataset name. Required. + :vartype name: str + :ivar version: Dataset version. Required. + :vartype version: str """ - treatment_run_id: str = rest_field( - name="treatmentRunId", visibility=["read", "create", "update", "delete", "query"] - ) - """The treatment run ID. Required.""" - treatment_run_summary: "_models.EvalRunResultSummary" = rest_field( - name="treatmentRunSummary", visibility=["read", "create", "update", "delete", "query"] - ) - """Summary statistics of the treatment run. Required.""" - delta_estimate: float = rest_field(name="deltaEstimate", visibility=["read", "create", "update", "delete", "query"]) - """Estimated difference between treatment and baseline. Required.""" - p_value: float = rest_field(name="pValue", visibility=["read", "create", "update", "delete", "query"]) - """P-value for the treatment effect. Required.""" - treatment_effect: Union[str, "_models.TreatmentEffectType"] = rest_field( - name="treatmentEffect", visibility=["read", "create", "update", "delete", "query"] - ) - """Type of treatment effect. Required. Known values are: \"TooFewSamples\", \"Inconclusive\", - \"Changed\", \"Improved\", and \"Degraded\".""" + 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.""" @overload def __init__( self, *, - treatment_run_id: str, - treatment_run_summary: "_models.EvalRunResultSummary", - delta_estimate: float, - p_value: float, - treatment_effect: Union[str, "_models.TreatmentEffectType"], + name: str, + version: str, ) -> None: ... @overload @@ -4277,47 +5002,67 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalRunResultComparison(_Model): - """Comparison results for treatment runs against the baseline. +class DatasetVersion(_Model): + """DatasetVersion Definition. - :ivar testing_criteria: Name of the testing criteria. Required. - :vartype testing_criteria: str - :ivar metric: Metric being evaluated. Required. - :vartype metric: str - :ivar evaluator: Name of the evaluator for this testing criteria. Required. - :vartype evaluator: str - :ivar baseline_run_summary: Summary statistics of the baseline run. Required. - :vartype baseline_run_summary: ~azure.ai.projects.models.EvalRunResultSummary - :ivar compare_items: List of comparison results for each treatment run. Required. - :vartype compare_items: list[~azure.ai.projects.models.EvalRunResultCompareItem] + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + FileDatasetVersion, FolderDatasetVersion + + :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 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] """ - testing_criteria: str = rest_field( - name="testingCriteria", visibility=["read", "create", "update", "delete", "query"] - ) - """Name of the testing criteria. Required.""" - metric: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Metric being evaluated. Required.""" - evaluator: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Name of the evaluator for this testing criteria. Required.""" - baseline_run_summary: "_models.EvalRunResultSummary" = rest_field( - name="baselineRunSummary", visibility=["read", "create", "update", "delete", "query"] - ) - """Summary statistics of the baseline run. Required.""" - compare_items: list["_models.EvalRunResultCompareItem"] = rest_field( - name="compareItems", visibility=["read", "create", "update", "delete", "query"] - ) - """List of comparison results for each treatment run. Required.""" + __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, *, - testing_criteria: str, - metric: str, - evaluator: str, - baseline_run_summary: "_models.EvalRunResultSummary", - compare_items: list["_models.EvalRunResultCompareItem"], + data_uri: str, + type: str, + connection_name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -4331,38 +5076,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalRunResultSummary(_Model): - """Summary statistics of a metric in an evaluation run. +class DeleteAgentResponse(_Model): + """A deleted agent Object. - :ivar run_id: The evaluation run ID. Required. - :vartype run_id: str - :ivar sample_count: Number of samples in the evaluation run. Required. - :vartype sample_count: int - :ivar average: Average value of the metric in the evaluation run. Required. - :vartype average: float - :ivar standard_deviation: Standard deviation of the metric in the evaluation run. Required. - :vartype standard_deviation: float + :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 """ - run_id: str = rest_field(name="runId", visibility=["read", "create", "update", "delete", "query"]) - """The evaluation run ID. Required.""" - sample_count: int = rest_field(name="sampleCount", visibility=["read", "create", "update", "delete", "query"]) - """Number of samples in the evaluation run. Required.""" - average: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Average value of the metric in the evaluation run. Required.""" - standard_deviation: float = rest_field( - name="standardDeviation", visibility=["read", "create", "update", "delete", "query"] + object: Literal[AgentObjectType.AGENT_DELETED] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Standard deviation of the metric in the evaluation run. Required.""" + """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, *, - run_id: str, - sample_count: int, - average: float, - standard_deviation: float, + object: Literal[AgentObjectType.AGENT_DELETED], + name: str, + deleted: bool, ) -> None: ... @overload @@ -4376,37 +5116,38 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationComparisonInsightRequest(InsightRequest, discriminator="EvaluationComparison"): - """Evaluation Comparison Request. +class DeleteAgentVersionResponse(_Model): + """A deleted agent version Object. - :ivar type: The type of request. Required. Evaluation Comparison. - :vartype type: str or ~azure.ai.projects.models.EVALUATION_COMPARISON - :ivar eval_id: Identifier for the evaluation. Required. - :vartype eval_id: str - :ivar baseline_run_id: The baseline run ID for comparison. Required. - :vartype baseline_run_id: str - :ivar treatment_run_ids: List of treatment run IDs for comparison. Required. - :vartype treatment_run_ids: list[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 """ - type: Literal[InsightType.EVALUATION_COMPARISON] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of request. Required. Evaluation Comparison.""" - eval_id: str = rest_field(name="evalId", visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the evaluation. Required.""" - baseline_run_id: str = rest_field(name="baselineRunId", visibility=["read", "create", "update", "delete", "query"]) - """The baseline run ID for comparison. Required.""" - treatment_run_ids: list[str] = rest_field( - name="treatmentRunIds", visibility=["read", "create", "update", "delete", "query"] + object: Literal[AgentObjectType.AGENT_VERSION_DELETED] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """List of treatment run IDs for comparison. Required.""" + """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, *, - eval_id: str, - baseline_run_id: str, - treatment_run_ids: list[str], + object: Literal[AgentObjectType.AGENT_VERSION_DELETED], + name: str, + version: str, + deleted: bool, ) -> None: ... @overload @@ -4418,35 +5159,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = InsightType.EVALUATION_COMPARISON # type: ignore -class EvaluationComparisonInsightResult(InsightResult, discriminator="EvaluationComparison"): - """Insights from the evaluation comparison. +class DeleteMemoryResult(_Model): + """Response for deleting a memory item from a memory store. - :ivar type: The type of insights result. Required. Evaluation Comparison. - :vartype type: str or ~azure.ai.projects.models.EVALUATION_COMPARISON - :ivar comparisons: Comparison results for each treatment run against the baseline. Required. - :vartype comparisons: list[~azure.ai.projects.models.EvalRunResultComparison] - :ivar method: The statistical method used for comparison. Required. - :vartype method: 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[InsightType.EVALUATION_COMPARISON] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of insights result. Required. Evaluation Comparison.""" - comparisons: list["_models.EvalRunResultComparison"] = rest_field( + object: Literal[MemoryStoreObjectType.MEMORY_DELETED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Comparison results for each treatment run against the baseline. Required.""" - method: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The statistical method used for comparison. Required.""" + """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, *, - comparisons: list["_models.EvalRunResultComparison"], - method: str, + object: Literal[MemoryStoreObjectType.MEMORY_DELETED], + memory_id: str, + deleted: bool, ) -> None: ... @overload @@ -4458,45 +5199,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = InsightType.EVALUATION_COMPARISON # type: ignore -class InsightSample(_Model): - """A sample from the analysis. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - EvaluationResultSample +class DeleteMemoryStoreResult(_Model): + """DeleteMemoryStoreResult. - :ivar id: The unique identifier for the analysis sample. Required. - :vartype id: str - :ivar type: Sample type. Required. "EvaluationResultSample" - :vartype type: str or ~azure.ai.projects.models.SampleType - :ivar features: Features to help with additional filtering of data in UX. Required. - :vartype features: dict[str, any] - :ivar correlation_info: Info about the correlation for the analysis sample. Required. - :vartype correlation_info: dict[str, any] + :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 """ - __mapping__: dict[str, _Model] = {} - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique identifier for the analysis sample. Required.""" - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Sample type. Required. \"EvaluationResultSample\"""" - features: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Features to help with additional filtering of data in UX. Required.""" - correlation_info: dict[str, Any] = rest_field( - name="correlationInfo", visibility=["read", "create", "update", "delete", "query"] + object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Info about the correlation for the analysis sample. Required.""" + """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, *, - id: str, # pylint: disable=redefined-builtin - type: str, - features: dict[str, Any], - correlation_info: dict[str, Any], + object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED], + name: str, + deleted: bool, ) -> None: ... @overload @@ -4510,36 +5241,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationResultSample(InsightSample, discriminator="EvaluationResultSample"): - """A sample from the evaluation result. - - :ivar id: The unique identifier for the analysis sample. Required. - :vartype id: str - :ivar features: Features to help with additional filtering of data in UX. Required. - :vartype features: dict[str, any] - :ivar correlation_info: Info about the correlation for the analysis sample. Required. - :vartype correlation_info: dict[str, any] - :ivar type: Evaluation Result Sample Type. Required. A sample from the evaluation result. - :vartype type: str or ~azure.ai.projects.models.EVALUATION_RESULT_SAMPLE - :ivar evaluation_result: Evaluation result for the analysis sample. Required. - :vartype evaluation_result: ~azure.ai.projects.models.EvalResult - """ +class DeleteSkillResult(_Model): + """A deleted skill Object. - type: Literal[SampleType.EVALUATION_RESULT_SAMPLE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Evaluation Result Sample Type. Required. A sample from the evaluation result.""" - evaluation_result: "_models.EvalResult" = rest_field( - name="evaluationResult", visibility=["read", "create", "update", "delete", "query"] - ) - """Evaluation result for the analysis sample. Required.""" + :ivar name: The unique name of the skill. Required. + :vartype name: str + :ivar deleted: Whether the skill was successfully deleted. Required. + :vartype deleted: bool + """ + + 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, *, - id: str, # pylint: disable=redefined-builtin - features: dict[str, Any], - correlation_info: dict[str, Any], - evaluation_result: "_models.EvalResult", + name: str, + deleted: bool, ) -> None: ... @overload @@ -4551,65 +5272,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = SampleType.EVALUATION_RESULT_SAMPLE # type: ignore -class EvaluationRule(_Model): - """Evaluation rule model. +class Deployment(_Model): + """Model Deployment Definition. - :ivar id: Unique identifier for the evaluation rule. Required. - :vartype id: str - :ivar display_name: Display Name for the evaluation rule. - :vartype display_name: str - :ivar description: Description for the evaluation rule. - :vartype description: str - :ivar action: Definition of the evaluation rule action. Required. - :vartype action: ~azure.ai.projects.models.EvaluationRuleAction - :ivar filter: Filter condition of the evaluation rule. - :vartype filter: ~azure.ai.projects.models.EvaluationRuleFilter - :ivar event_type: Event type that the evaluation rule applies to. Required. Known values are: - "responseCompleted" and "manual". - :vartype event_type: str or ~azure.ai.projects.models.EvaluationRuleEventType - :ivar enabled: Indicates whether the evaluation rule is enabled. Default is true. Required. - :vartype enabled: bool - :ivar system_data: System metadata for the evaluation rule. Required. - :vartype system_data: dict[str, str] + 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 """ - id: str = rest_field(visibility=["read"]) - """Unique identifier for the evaluation rule. Required.""" - display_name: Optional[str] = rest_field( - name="displayName", visibility=["read", "create", "update", "delete", "query"] - ) - """Display Name for the evaluation rule.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description for the evaluation rule.""" - action: "_models.EvaluationRuleAction" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Definition of the evaluation rule action. Required.""" - filter: Optional["_models.EvaluationRuleFilter"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Filter condition of the evaluation rule.""" - event_type: Union[str, "_models.EvaluationRuleEventType"] = rest_field( - name="eventType", visibility=["read", "create", "update", "delete", "query"] - ) - """Event type that the evaluation rule applies to. Required. Known values are: - \"responseCompleted\" and \"manual\".""" - enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Indicates whether the evaluation rule is enabled. Default is true. Required.""" - system_data: dict[str, str] = rest_field(name="systemData", visibility=["read"]) - """System metadata for the evaluation rule. 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, *, - action: "_models.EvaluationRuleAction", - event_type: Union[str, "_models.EvaluationRuleEventType"], - enabled: bool, - display_name: Optional[str] = None, - description: Optional[str] = None, - filter: Optional["_models.EvaluationRuleFilter"] = None, # pylint: disable=redefined-builtin + type: str, ) -> None: ... @overload @@ -4623,21 +5310,54 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationRuleFilter(_Model): - """Evaluation filter model. +class Dimension(_Model): + """A single dimension — one independent, measurable quality dimension within a rubric evaluator's + scoring blueprint. - :ivar agent_name: Filter by agent name. Required. - :vartype agent_name: str + :ivar id: Stable identifier for this dimension (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 set; the generation pipeline produces an initial value + the user can edit. Editable when saving new versions. Required. + :vartype id: str + :ivar description: What this dimension 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 dimension (1-10). The generation pipeline assigns exactly + one dimension 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 dimension regardless of + relevance (skips applicability assessment). The service-generated general quality/policy + dimension has this set to true and is non-editable. Users may set this on their own custom + dimensions. Defaults to ``false``. + :vartype always_applicable: bool """ - agent_name: str = rest_field(name="agentName", visibility=["read", "create", "update", "delete", "query"]) - """Filter by agent name. Required.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Stable identifier for this dimension (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 set; 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 dimension 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 dimension (1-10). The generation pipeline assigns exactly one dimension + 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 dimension regardless of relevance (skips + applicability assessment). The service-generated general quality/policy dimension has this set + to true and is non-editable. Users may set this on their own custom dimensions. Defaults to + ``false``.""" @overload def __init__( self, *, - agent_name: str, + id: str, # pylint: disable=redefined-builtin + description: str, + weight: int, + always_applicable: Optional[bool] = None, ) -> None: ... @overload @@ -4651,37 +5371,31 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationRunClusterInsightRequest(InsightRequest, discriminator="EvaluationRunClusterInsight"): - """Insights on set of Evaluation Results. +class DispatchRoutineResult(_Model): + """Identifiers returned after a routine dispatch is queued. - :ivar type: The type of insights request. Required. Insights on an Evaluation run result. - :vartype type: str or ~azure.ai.projects.models.EVALUATION_RUN_CLUSTER_INSIGHT - :ivar eval_id: Evaluation Id for the insights. Required. - :vartype eval_id: str - :ivar run_ids: List of evaluation run IDs for the insights. Required. - :vartype run_ids: list[str] - :ivar model_configuration: Configuration of the model used in the insight generation. - :vartype model_configuration: ~azure.ai.projects.models.InsightModelConfiguration + :ivar dispatch_id: The dispatch identifier created for the routine dispatch. + :vartype dispatch_id: str + :ivar action_correlation_id: A downstream action correlation identifier, when available. + :vartype action_correlation_id: str + :ivar task_id: A workspace task identifier created for the dispatch, when available. + :vartype task_id: str """ - type: Literal[InsightType.EVALUATION_RUN_CLUSTER_INSIGHT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of insights request. Required. Insights on an Evaluation run result.""" - eval_id: str = rest_field(name="evalId", visibility=["read", "create", "update", "delete", "query"]) - """Evaluation Id for the insights. Required.""" - run_ids: list[str] = rest_field(name="runIds", visibility=["read", "create", "update", "delete", "query"]) - """List of evaluation run IDs for the insights. Required.""" - model_configuration: Optional["_models.InsightModelConfiguration"] = rest_field( - name="modelConfiguration", visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration of the model used in the insight generation.""" + dispatch_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The dispatch identifier created for the routine dispatch.""" + action_correlation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A downstream action correlation identifier, when available.""" + task_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A workspace task identifier created for the dispatch, when available.""" @overload def __init__( self, *, - eval_id: str, - run_ids: list[str], - model_configuration: Optional["_models.InsightModelConfiguration"] = None, + dispatch_id: Optional[str] = None, + action_correlation_id: Optional[str] = None, + task_id: Optional[str] = None, ) -> None: ... @overload @@ -4693,30 +5407,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = InsightType.EVALUATION_RUN_CLUSTER_INSIGHT # type: ignore -class EvaluationRunClusterInsightResult(InsightResult, discriminator="EvaluationRunClusterInsight"): - """Insights from the evaluation run cluster analysis. +class EmbeddingConfiguration(_Model): + """Embedding configuration class. - :ivar type: The type of insights result. Required. Insights on an Evaluation run result. - :vartype type: str or ~azure.ai.projects.models.EVALUATION_RUN_CLUSTER_INSIGHT - :ivar cluster_insight: Required. - :vartype cluster_insight: ~azure.ai.projects.models.ClusterInsightResult + :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[InsightType.EVALUATION_RUN_CLUSTER_INSIGHT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of insights result. Required. Insights on an Evaluation run result.""" - cluster_insight: "_models.ClusterInsightResult" = rest_field( - name="clusterInsight", visibility=["read", "create", "update", "delete", "query"] - ) - """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, *, - cluster_insight: "_models.ClusterInsightResult", + model_deployment_name: str, + embedding_field: str, ) -> None: ... @overload @@ -4728,33 +5442,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = InsightType.EVALUATION_RUN_CLUSTER_INSIGHT # type: ignore -class ScheduleTask(_Model): - """Schedule task model. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - EvaluationScheduleTask, InsightScheduleTask +class EntraAuthorizationScheme(AgentEndpointAuthorizationScheme, discriminator="Entra"): + """EntraAuthorizationScheme. - :ivar type: Type of the task. Required. Known values are: "Evaluation" and "Insight". - :vartype type: str or ~azure.ai.projects.models.ScheduleTaskType - :ivar configuration: Configuration for the task. - :vartype configuration: dict[str, str] + :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 """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Type of the task. Required. Known values are: \"Evaluation\" and \"Insight\".""" - configuration: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Configuration for the task.""" + 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, *, - type: str, - configuration: Optional[dict[str, str]] = None, + isolation_key_source: Optional["_models.IsolationKeySource"] = None, ) -> None: ... @overload @@ -4766,35 +5478,22 @@ 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 -class EvaluationScheduleTask(ScheduleTask, discriminator="Evaluation"): - """Evaluation task for the schedule. +class EntraIDCredentials(BaseCredentials, discriminator="AAD"): + """Entra ID credential definition. - :ivar configuration: Configuration for the task. - :vartype configuration: dict[str, str] - :ivar type: Required. Evaluation task. - :vartype type: str or ~azure.ai.projects.models.EVALUATION - :ivar eval_id: Identifier of the evaluation group. Required. - :vartype eval_id: str - :ivar eval_run: The evaluation run payload. Required. - :vartype eval_run: any + :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[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[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, - *, - eval_id: str, - eval_run: Any, - configuration: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -4806,60 +5505,28 @@ 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 + self.type = CredentialType.ENTRA_ID # type: ignore -class EvaluationTaxonomy(_Model): - """Evaluation Taxonomy Definition. +class IsolationKeySource(_Model): + """IsolationKeySource. - :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] + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + EntraIsolationKeySource, HeaderIsolationKeySource + + :ivar kind: Required. Known values are: "Entra" and "Header". + :vartype kind: str or ~azure.ai.projects.models.IsolationKeySourceKind """ - 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.""" + __mapping__: dict[str, _Model] = {} + kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"Entra\" and \"Header\".""" @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, + kind: str, ) -> None: ... @overload @@ -4873,52 +5540,19 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluatorMetric(_Model): - """Evaluator Metric. +class EntraIsolationKeySource(IsolationKeySource, discriminator="Entra"): + """EntraIsolationKeySource. - :ivar type: Type of the metric. Known values are: "ordinal", "continuous", and "boolean". - :vartype type: str or ~azure.ai.projects.models.EvaluatorMetricType - :ivar desirable_direction: It indicates whether a higher value is better or a lower value is - better for this metric. Known values are: "increase", "decrease", and "neutral". - :vartype desirable_direction: str or ~azure.ai.projects.models.EvaluatorMetricDirection - :ivar min_value: Minimum value for the metric. - :vartype min_value: float - :ivar max_value: Maximum value for the metric. If not specified, it is assumed to be unbounded. - :vartype max_value: float - :ivar threshold: Default pass/fail threshold for this metric. - :vartype threshold: float - :ivar is_primary: Indicates if this metric is primary when there are multiple metrics. - :vartype is_primary: bool + :ivar kind: Required. ENTRA. + :vartype kind: str or ~azure.ai.projects.models.ENTRA """ - type: Optional[Union[str, "_models.EvaluatorMetricType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Type of the metric. Known values are: \"ordinal\", \"continuous\", and \"boolean\".""" - desirable_direction: Optional[Union[str, "_models.EvaluatorMetricDirection"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """It indicates whether a higher value is better or a lower value is better for this metric. Known - values are: \"increase\", \"decrease\", and \"neutral\".""" - min_value: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Minimum value for the metric.""" - max_value: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum value for the metric. If not specified, it is assumed to be unbounded.""" - threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Default pass/fail threshold for this metric.""" - is_primary: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Indicates if this metric is primary when there are multiple metrics.""" + kind: Literal[IsolationKeySourceKind.ENTRA] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. ENTRA.""" @overload def __init__( self, - *, - type: Optional[Union[str, "_models.EvaluatorMetricType"]] = None, - desirable_direction: Optional[Union[str, "_models.EvaluatorMetricDirection"]] = None, - min_value: Optional[float] = None, - max_value: Optional[float] = None, - threshold: Optional[float] = None, - is_primary: Optional[bool] = None, ) -> None: ... @overload @@ -4930,82 +5564,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.kind = IsolationKeySourceKind.ENTRA # type: ignore -class EvaluatorVersion(_Model): - """Evaluator Definition. +class EvalResult(_Model): + """Result of the evaluation. - :ivar display_name: Display Name for evaluator. It helps to find the evaluator easily in AI - Foundry. It does not need to be unique. - :vartype display_name: str - :ivar metadata: Metadata about the evaluator. - :vartype metadata: dict[str, str] - :ivar evaluator_type: The type of the evaluator. Required. Known values are: "builtin" and - "custom". - :vartype evaluator_type: str or ~azure.ai.projects.models.EvaluatorType - :ivar categories: The categories of the evaluator. Required. - :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 created_by: Creator of the evaluator. Required. - :vartype created_by: str - :ivar created_at: Creation date/time of the evaluator. Required. - :vartype created_at: ~datetime.datetime - :ivar modified_at: Last modified date/time of the evaluator. Required. - :vartype modified_at: ~datetime.datetime - :ivar id: Asset ID, a unique identifier for the asset. - :vartype id: str - :ivar name: The name of the resource. Required. + :ivar name: name of the check. 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 type: type of the check. Required. + :vartype type: str + :ivar score: score. Required. + :vartype score: float + :ivar passed: indicates if the check passed or failed. Required. + :vartype passed: bool """ - display_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Display Name for evaluator. It helps to find the evaluator easily in AI Foundry. It does not - need to be unique.""" - metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Metadata about the evaluator.""" - evaluator_type: Union[str, "_models.EvaluatorType"] = rest_field(visibility=["read", "create"]) - """The type of the evaluator. Required. Known values are: \"builtin\" and \"custom\".""" - categories: list[Union[str, "_models.EvaluatorCategory"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The categories of the evaluator. Required.""" - definition: "_models.EvaluatorDefinition" = rest_field(visibility=["read", "create"]) - """Definition of the evaluator. Required.""" - created_by: str = rest_field(visibility=["read"]) - """Creator of the evaluator. Required.""" - created_at: datetime.datetime = rest_field(visibility=["read"], format="rfc3339") - """Creation date/time of the evaluator. Required.""" - modified_at: datetime.datetime = rest_field(visibility=["read"], format="rfc3339") - """Last modified date/time of the evaluator. 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.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """name of the check. Required.""" + type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """type of the check. Required.""" + score: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """score. Required.""" + passed: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """indicates if the check passed or failed. Required.""" @overload def __init__( self, *, - evaluator_type: Union[str, "_models.EvaluatorType"], - categories: list[Union[str, "_models.EvaluatorCategory"]], - definition: "_models.EvaluatorDefinition", - display_name: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + name: str, + type: str, + score: float, + passed: bool, ) -> None: ... @overload @@ -5019,25 +5610,80 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FabricDataAgentToolParameters(_Model): - """The fabric data agent tool parameters. +class EvalRunOutputItemResult(_Model): + """EvalRunOutputItemResult. - :ivar project_connections: The project connections attached to this tool. There can be a - maximum of 1 connection resource attached to the tool. - :vartype project_connections: list[~azure.ai.projects.models.ToolProjectConnection] + :ivar name: The name of the grader. Required. + :vartype name: str + :ivar type: The grader type (for example, "string-check-grader"). + :vartype type: str + :ivar score: The numeric score produced by the grader. Required. + :vartype score: int + :ivar passed: Whether the grader considered the output a pass. Required. + :vartype passed: bool + :ivar sample: Optional sample or intermediate data produced by the grader. + :vartype sample: dict[str, any] + :ivar status: The evaluation status for this result item. Values: "completed", "errored", + "skipped". Null if not provided by evaluator. When status is skipped, passed/score can be + ignored. Known values are: "completed", "errored", and "skipped". + :vartype status: str or ~azure.ai.projects.models.EvalRunOutputItemResultStatus + :ivar metric: The name of the metric (e.g., "fluency", "f1_score"). + :vartype metric: str + :ivar label: The label associated with the test criteria metric (e.g., "pass", "fail", "good", + "bad"). + :vartype label: str + :ivar threshold: The threshold used to determine pass/fail for this test criteria, if it is + numerical. + :vartype threshold: float + :ivar reason: The reason for the test criteria metric. + :vartype reason: str + :ivar properties: Additional details about the test criteria metric. + :vartype properties: dict[str, str] """ - project_connections: Optional[list["_models.ToolProjectConnection"]] = rest_field( + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the grader. Required.""" + type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The grader type (for example, \"string-check-grader\").""" + score: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The numeric score produced by the grader. Required.""" + passed: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the grader considered the output a pass. Required.""" + sample: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional sample or intermediate data produced by the grader.""" + status: Optional[Union[str, "_models.EvalRunOutputItemResultStatus"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The project connections attached to this tool. There can be a maximum of 1 connection resource - attached to the tool.""" + """The evaluation status for this result item. Values: \"completed\", \"errored\", \"skipped\". + Null if not provided by evaluator. When status is skipped, passed/score can be ignored. Known + values are: \"completed\", \"errored\", and \"skipped\".""" + metric: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the metric (e.g., \"fluency\", \"f1_score\").""" + label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The label associated with the test criteria metric (e.g., \"pass\", \"fail\", \"good\", + \"bad\").""" + threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The threshold used to determine pass/fail for this test criteria, if it is numerical.""" + reason: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The reason for the test criteria metric.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Additional details about the test criteria metric.""" @overload def __init__( self, *, - project_connections: Optional[list["_models.ToolProjectConnection"]] = None, + name: str, + score: int, + passed: bool, + type: Optional[str] = None, + sample: Optional[dict[str, Any]] = None, + status: Optional[Union[str, "_models.EvalRunOutputItemResultStatus"]] = None, + metric: Optional[str] = None, + label: Optional[str] = None, + threshold: Optional[float] = None, + reason: Optional[str] = None, + properties: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -5051,46 +5697,49 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FieldMapping(_Model): - """Field mapping configuration class. +class EvalRunResultCompareItem(_Model): + """Metric comparison for a treatment against the baseline. - :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] + :ivar treatment_run_id: The treatment run ID. Required. + :vartype treatment_run_id: str + :ivar treatment_run_summary: Summary statistics of the treatment run. Required. + :vartype treatment_run_summary: ~azure.ai.projects.models.EvalRunResultSummary + :ivar delta_estimate: Estimated difference between treatment and baseline. Required. + :vartype delta_estimate: float + :ivar p_value: P-value for the treatment effect. Required. + :vartype p_value: float + :ivar treatment_effect: Type of treatment effect. Required. Known values are: "TooFewSamples", + "Inconclusive", "Changed", "Improved", and "Degraded". + :vartype treatment_effect: str or ~azure.ai.projects.models.TreatmentEffectType """ - 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.""" + treatment_run_id: str = rest_field( + name="treatmentRunId", visibility=["read", "create", "update", "delete", "query"] + ) + """The treatment run ID. Required.""" + treatment_run_summary: "_models.EvalRunResultSummary" = rest_field( + name="treatmentRunSummary", visibility=["read", "create", "update", "delete", "query"] + ) + """Summary statistics of the treatment run. Required.""" + delta_estimate: float = rest_field(name="deltaEstimate", visibility=["read", "create", "update", "delete", "query"]) + """Estimated difference between treatment and baseline. Required.""" + p_value: float = rest_field(name="pValue", visibility=["read", "create", "update", "delete", "query"]) + """P-value for the treatment effect. Required.""" + treatment_effect: Union[str, "_models.TreatmentEffectType"] = rest_field( + name="treatmentEffect", visibility=["read", "create", "update", "delete", "query"] + ) + """Type of treatment effect. Required. Known values are: \"TooFewSamples\", \"Inconclusive\", + \"Changed\", \"Improved\", and \"Degraded\".""" @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, + treatment_run_id: str, + treatment_run_summary: "_models.EvalRunResultSummary", + delta_estimate: float, + p_value: float, + treatment_effect: Union[str, "_models.TreatmentEffectType"], ) -> None: ... @overload @@ -5104,44 +5753,47 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileDatasetVersion(DatasetVersion, discriminator="uri_file"): - """FileDatasetVersion Definition. +class EvalRunResultComparison(_Model): + """Comparison results for treatment runs against the baseline. - :ivar data_uri: URI of the data (`example `_). - Required. - :vartype data_uri: str - :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 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 type: Dataset type. Required. URI file. - :vartype type: str or ~azure.ai.projects.models.URI_FILE + :ivar testing_criteria: Name of the testing criteria. Required. + :vartype testing_criteria: str + :ivar metric: Metric being evaluated. Required. + :vartype metric: str + :ivar evaluator: Name of the evaluator for this testing criteria. Required. + :vartype evaluator: str + :ivar baseline_run_summary: Summary statistics of the baseline run. Required. + :vartype baseline_run_summary: ~azure.ai.projects.models.EvalRunResultSummary + :ivar compare_items: List of comparison results for each treatment run. Required. + :vartype compare_items: list[~azure.ai.projects.models.EvalRunResultCompareItem] """ - type: Literal[DatasetType.URI_FILE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Dataset type. Required. URI file.""" + testing_criteria: str = rest_field( + name="testingCriteria", visibility=["read", "create", "update", "delete", "query"] + ) + """Name of the testing criteria. Required.""" + metric: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Metric being evaluated. Required.""" + evaluator: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name of the evaluator for this testing criteria. Required.""" + baseline_run_summary: "_models.EvalRunResultSummary" = rest_field( + name="baselineRunSummary", visibility=["read", "create", "update", "delete", "query"] + ) + """Summary statistics of the baseline run. Required.""" + compare_items: list["_models.EvalRunResultCompareItem"] = rest_field( + name="compareItems", visibility=["read", "create", "update", "delete", "query"] + ) + """List of comparison results for each treatment run. Required.""" @overload def __init__( self, *, - data_uri: str, - connection_name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + testing_criteria: str, + metric: str, + evaluator: str, + baseline_run_summary: "_models.EvalRunResultSummary", + compare_items: list["_models.EvalRunResultCompareItem"], ) -> None: ... @overload @@ -5153,57 +5805,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DatasetType.URI_FILE # type: ignore -class FileSearchTool(Tool, discriminator="file_search"): - """File search. +class EvalRunResultSummary(_Model): + """Summary statistics of a metric in an evaluation run. - :ivar type: The type of the file search tool. Always ``file_search``. Required. FILE_SEARCH. - :vartype type: str or ~azure.ai.projects.models.FILE_SEARCH - :ivar vector_store_ids: The IDs of the vector stores to search. Required. - :vartype vector_store_ids: list[str] - :ivar max_num_results: The maximum number of results to return. This number should be between 1 - and 50 inclusive. - :vartype max_num_results: int - :ivar ranking_options: Ranking options for search. - :vartype ranking_options: ~azure.ai.projects.models.RankingOptions - :ivar filters: Is either a ComparisonFilter type or a CompoundFilter type. - :vartype filters: ~azure.ai.projects.models.ComparisonFilter or - ~azure.ai.projects.models.CompoundFilter - :ivar name: Optional user-defined name for this tool or configuration. - :vartype name: str - :ivar description: Optional user-defined description for this tool or configuration. - :vartype description: str + :ivar run_id: The evaluation run ID. Required. + :vartype run_id: str + :ivar sample_count: Number of samples in the evaluation run. Required. + :vartype sample_count: int + :ivar average: Average value of the metric in the evaluation run. Required. + :vartype average: float + :ivar standard_deviation: Standard deviation of the metric in the evaluation run. Required. + :vartype standard_deviation: float """ - type: Literal[ToolType.FILE_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the file search tool. Always ``file_search``. Required. FILE_SEARCH.""" - vector_store_ids: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The IDs of the vector stores to search. Required.""" - max_num_results: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The maximum number of results to return. This number should be between 1 and 50 inclusive.""" - ranking_options: Optional["_models.RankingOptions"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + run_id: str = rest_field(name="runId", visibility=["read", "create", "update", "delete", "query"]) + """The evaluation run ID. Required.""" + sample_count: int = rest_field(name="sampleCount", visibility=["read", "create", "update", "delete", "query"]) + """Number of samples in the evaluation run. Required.""" + average: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Average value of the metric in the evaluation run. Required.""" + standard_deviation: float = rest_field( + name="standardDeviation", visibility=["read", "create", "update", "delete", "query"] ) - """Ranking options for search.""" - filters: Optional["_types.Filters"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Is either a ComparisonFilter type or a CompoundFilter type.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined name for this tool or configuration.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined description for this tool or configuration.""" + """Standard deviation of the metric in the evaluation run. Required.""" @overload def __init__( self, *, - vector_store_ids: list[str], - max_num_results: Optional[int] = None, - ranking_options: Optional["_models.RankingOptions"] = None, - filters: Optional["_types.Filters"] = None, - name: Optional[str] = None, - description: Optional[str] = None, + run_id: str, + sample_count: int, + average: float, + standard_deviation: float, ) -> None: ... @overload @@ -5215,33 +5850,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.FILE_SEARCH # type: ignore -class VersionSelectionRule(_Model): - """VersionSelectionRule. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - FixedRatioVersionSelectionRule +class EvaluationComparisonInsightRequest(InsightRequest, discriminator="EvaluationComparison"): + """Evaluation Comparison Request. - :ivar type: Required. "FixedRatio" - :vartype type: str or ~azure.ai.projects.models.VersionSelectorType - :ivar agent_version: The agent version to route traffic to. Required. - :vartype agent_version: str + :ivar type: The type of request. Required. Evaluation Comparison. + :vartype type: str or ~azure.ai.projects.models.EVALUATION_COMPARISON + :ivar eval_id: Identifier for the evaluation. Required. + :vartype eval_id: str + :ivar baseline_run_id: The baseline run ID for comparison. Required. + :vartype baseline_run_id: str + :ivar treatment_run_ids: List of treatment run IDs for comparison. Required. + :vartype treatment_run_ids: list[str] """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. \"FixedRatio\"""" - agent_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent version to route traffic to. Required.""" + type: Literal[InsightType.EVALUATION_COMPARISON] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of request. Required. Evaluation Comparison.""" + eval_id: str = rest_field(name="evalId", visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the evaluation. Required.""" + baseline_run_id: str = rest_field(name="baselineRunId", visibility=["read", "create", "update", "delete", "query"]) + """The baseline run ID for comparison. Required.""" + treatment_run_ids: list[str] = rest_field( + name="treatmentRunIds", visibility=["read", "create", "update", "delete", "query"] + ) + """List of treatment run IDs for comparison. Required.""" @overload def __init__( self, *, - type: str, - agent_version: str, + eval_id: str, + baseline_run_id: str, + treatment_run_ids: list[str], ) -> None: ... @overload @@ -5253,31 +5894,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = InsightType.EVALUATION_COMPARISON # type: ignore -class FixedRatioVersionSelectionRule(VersionSelectionRule, discriminator="FixedRatio"): - """FixedRatioVersionSelectionRule. +class EvaluationComparisonInsightResult(InsightResult, discriminator="EvaluationComparison"): + """Insights from the evaluation comparison. - :ivar agent_version: The agent version to route traffic to. Required. - :vartype agent_version: str - :ivar type: Required. FIXED_RATIO. - :vartype type: str or ~azure.ai.projects.models.FIXED_RATIO - :ivar traffic_percentage: The percentage of traffic to route to the version. Must be between 0 - and 100. Required. - :vartype traffic_percentage: int + :ivar type: The type of insights result. Required. Evaluation Comparison. + :vartype type: str or ~azure.ai.projects.models.EVALUATION_COMPARISON + :ivar comparisons: Comparison results for each treatment run against the baseline. Required. + :vartype comparisons: list[~azure.ai.projects.models.EvalRunResultComparison] + :ivar method: The statistical method used for comparison. Required. + :vartype method: str """ - type: Literal[VersionSelectorType.FIXED_RATIO] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. FIXED_RATIO.""" - traffic_percentage: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The percentage of traffic to route to the version. Must be between 0 and 100. Required.""" + type: Literal[InsightType.EVALUATION_COMPARISON] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of insights result. Required. Evaluation Comparison.""" + comparisons: list["_models.EvalRunResultComparison"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Comparison results for each treatment run against the baseline. Required.""" + method: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The statistical method used for comparison. Required.""" @overload def __init__( self, *, - agent_version: str, - traffic_percentage: int, + comparisons: list["_models.EvalRunResultComparison"], + method: str, ) -> None: ... @overload @@ -5289,47 +5934,29 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = VersionSelectorType.FIXED_RATIO # type: ignore + self.type = InsightType.EVALUATION_COMPARISON # type: ignore -class FolderDatasetVersion(DatasetVersion, discriminator="uri_folder"): - """FileDatasetVersion Definition. +class EvaluationCriterion(_Model): + """LLM-as-judge evaluation criterion applied to a single task. - :ivar data_uri: URI of the data (`example `_). - Required. - :vartype data_uri: str - :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: Criterion name (referenced in evaluation result rows). 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 type: Dataset type. Required. URI folder. - :vartype type: str or ~azure.ai.projects.models.URI_FOLDER + :ivar instruction: Natural-language instruction passed to the judge LLM. Required. + :vartype instruction: str """ - type: Literal[DatasetType.URI_FOLDER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Dataset type. Required. URI folder.""" + 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, *, - data_uri: str, - connection_name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + name: str, + instruction: str, ) -> None: ... @overload @@ -5341,42 +5968,47 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DatasetType.URI_FOLDER # type: ignore -class FunctionShellToolParam(Tool, discriminator="shell"): - """Shell tool. +class InsightSample(_Model): + """A sample from the analysis. - :ivar type: The type of the shell tool. Always ``shell``. Required. SHELL. - :vartype type: str or ~azure.ai.projects.models.SHELL - :ivar environment: - :vartype environment: ~azure.ai.projects.models.FunctionShellToolParamEnvironment - :ivar name: Optional user-defined name for this tool or configuration. - :vartype name: str - :ivar description: Optional user-defined description for this tool or configuration. - :vartype description: str + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + EvaluationResultSample + + :ivar id: The unique identifier for the analysis sample. Required. + :vartype id: str + :ivar type: Sample type. Required. "EvaluationResultSample" + :vartype type: str or ~azure.ai.projects.models.SampleType + :ivar features: Features to help with additional filtering of data in UX. Required. + :vartype features: dict[str, any] + :ivar correlation_info: Info about the correlation for the analysis sample. Required. + :vartype correlation_info: dict[str, any] """ - type: Literal[ToolType.SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the shell tool. Always ``shell``. Required. SHELL.""" - environment: Optional["_models.FunctionShellToolParamEnvironment"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + __mapping__: dict[str, _Model] = {} + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier for the analysis sample. Required.""" + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Sample type. Required. \"EvaluationResultSample\"""" + features: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Features to help with additional filtering of data in UX. Required.""" + correlation_info: dict[str, Any] = rest_field( + name="correlationInfo", visibility=["read", "create", "update", "delete", "query"] ) - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined name for this tool or configuration.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined description for this tool or configuration.""" + """Info about the correlation for the analysis sample. Required.""" @overload def __init__( self, *, - environment: Optional["_models.FunctionShellToolParamEnvironment"] = None, - name: Optional[str] = None, - description: Optional[str] = None, - ) -> None: ... - - @overload + id: str, # pylint: disable=redefined-builtin + type: str, + features: dict[str, Any], + correlation_info: dict[str, Any], + ) -> None: ... + + @overload def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. @@ -5385,31 +6017,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.SHELL # type: ignore -class FunctionShellToolParamEnvironmentContainerReferenceParam( - FunctionShellToolParamEnvironment, discriminator="container_reference" -): # pylint: disable=name-too-long - """FunctionShellToolParamEnvironmentContainerReferenceParam. +class EvaluationResultSample(InsightSample, discriminator="EvaluationResultSample"): + """A sample from the evaluation result. - :ivar type: References a container created with the /v1/containers endpoint. Required. - CONTAINER_REFERENCE. - :vartype type: str or ~azure.ai.projects.models.CONTAINER_REFERENCE - :ivar container_id: The ID of the referenced container. Required. - :vartype container_id: str + :ivar id: The unique identifier for the analysis sample. Required. + :vartype id: str + :ivar features: Features to help with additional filtering of data in UX. Required. + :vartype features: dict[str, any] + :ivar correlation_info: Info about the correlation for the analysis sample. Required. + :vartype correlation_info: dict[str, any] + :ivar type: Evaluation Result Sample Type. Required. A sample from the evaluation result. + :vartype type: str or ~azure.ai.projects.models.EVALUATION_RESULT_SAMPLE + :ivar evaluation_result: Evaluation result for the analysis sample. Required. + :vartype evaluation_result: ~azure.ai.projects.models.EvalResult """ - type: Literal[FunctionShellToolParamEnvironmentType.CONTAINER_REFERENCE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """References a container created with the /v1/containers endpoint. Required. CONTAINER_REFERENCE.""" - container_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the referenced container. Required.""" + type: Literal[SampleType.EVALUATION_RESULT_SAMPLE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Evaluation Result Sample Type. Required. A sample from the evaluation result.""" + evaluation_result: "_models.EvalResult" = rest_field( + name="evaluationResult", visibility=["read", "create", "update", "delete", "query"] + ) + """Evaluation result for the analysis sample. Required.""" @overload def __init__( self, *, - container_id: str, + id: str, # pylint: disable=redefined-builtin + features: dict[str, Any], + correlation_info: dict[str, Any], + evaluation_result: "_models.EvalResult", ) -> None: ... @overload @@ -5421,32 +6060,65 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = FunctionShellToolParamEnvironmentType.CONTAINER_REFERENCE # type: ignore + self.type = SampleType.EVALUATION_RESULT_SAMPLE # type: ignore -class FunctionShellToolParamEnvironmentLocalEnvironmentParam( - FunctionShellToolParamEnvironment, discriminator="local" -): # pylint: disable=name-too-long - """FunctionShellToolParamEnvironmentLocalEnvironmentParam. +class EvaluationRule(_Model): + """Evaluation rule model. - :ivar type: Use a local computer environment. Required. LOCAL. - :vartype type: str or ~azure.ai.projects.models.LOCAL - :ivar skills: An optional list of skills. - :vartype skills: list[~azure.ai.projects.models.LocalSkillParam] + :ivar id: Unique identifier for the evaluation rule. Required. + :vartype id: str + :ivar display_name: Display Name for the evaluation rule. + :vartype display_name: str + :ivar description: Description for the evaluation rule. + :vartype description: str + :ivar action: Definition of the evaluation rule action. Required. + :vartype action: ~azure.ai.projects.models.EvaluationRuleAction + :ivar filter: Filter condition of the evaluation rule. + :vartype filter: ~azure.ai.projects.models.EvaluationRuleFilter + :ivar event_type: Event type that the evaluation rule applies to. Required. Known values are: + "responseCompleted" and "manual". + :vartype event_type: str or ~azure.ai.projects.models.EvaluationRuleEventType + :ivar enabled: Indicates whether the evaluation rule is enabled. Default is true. Required. + :vartype enabled: bool + :ivar system_data: System metadata for the evaluation rule. Required. + :vartype system_data: dict[str, str] """ - type: Literal[FunctionShellToolParamEnvironmentType.LOCAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Use a local computer environment. Required. LOCAL.""" - skills: Optional[list["_models.LocalSkillParam"]] = rest_field( + id: str = rest_field(visibility=["read"]) + """Unique identifier for the evaluation rule. Required.""" + display_name: Optional[str] = rest_field( + name="displayName", visibility=["read", "create", "update", "delete", "query"] + ) + """Display Name for the evaluation rule.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description for the evaluation rule.""" + action: "_models.EvaluationRuleAction" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Definition of the evaluation rule action. Required.""" + filter: Optional["_models.EvaluationRuleFilter"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """An optional list of skills.""" + """Filter condition of the evaluation rule.""" + event_type: Union[str, "_models.EvaluationRuleEventType"] = rest_field( + name="eventType", visibility=["read", "create", "update", "delete", "query"] + ) + """Event type that the evaluation rule applies to. Required. Known values are: + \"responseCompleted\" and \"manual\".""" + enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Indicates whether the evaluation rule is enabled. Default is true. Required.""" + system_data: dict[str, str] = rest_field(name="systemData", visibility=["read"]) + """System metadata for the evaluation rule. Required.""" @overload def __init__( self, *, - skills: Optional[list["_models.LocalSkillParam"]] = None, + action: "_models.EvaluationRuleAction", + event_type: Union[str, "_models.EvaluationRuleEventType"], + enabled: bool, + display_name: Optional[str] = None, + description: Optional[str] = None, + filter: Optional["_models.EvaluationRuleFilter"] = None, # pylint: disable=redefined-builtin ) -> None: ... @overload @@ -5458,42 +6130,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = FunctionShellToolParamEnvironmentType.LOCAL # type: ignore -class FunctionTool(Tool, discriminator="function"): - """Function. +class EvaluationRuleFilter(_Model): + """Evaluation filter model. - :ivar type: The type of the function tool. Always ``function``. Required. FUNCTION. - :vartype type: str or ~azure.ai.projects.models.FUNCTION - :ivar name: The name of the function to call. Required. - :vartype name: str - :ivar description: - :vartype description: str - :ivar parameters: Required. - :vartype parameters: dict[str, any] - :ivar strict: Required. - :vartype strict: bool + :ivar agent_name: Filter by agent name. Required. + :vartype agent_name: str """ - type: Literal[ToolType.FUNCTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the function tool. Always ``function``. Required. FUNCTION.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function to call. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - parameters: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - strict: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + agent_name: str = rest_field(name="agentName", visibility=["read", "create", "update", "delete", "query"]) + """Filter by agent name. Required.""" @overload def __init__( self, *, - name: str, - parameters: dict[str, Any], - strict: bool, - description: Optional[str] = None, + agent_name: str, ) -> None: ... @overload @@ -5505,33 +6158,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.FUNCTION # type: ignore -class HeaderIsolationKeySource(IsolationKeySource, discriminator="Header"): - """HeaderIsolationKeySource. +class EvaluationRunClusterInsightRequest(InsightRequest, discriminator="EvaluationRunClusterInsight"): + """Insights on set of Evaluation Results. - :ivar kind: Required. HEADER. - :vartype kind: str or ~azure.ai.projects.models.HEADER - :ivar user_isolation_key: The user isolation key header value. Required. - :vartype user_isolation_key: str - :ivar chat_isolation_key: The chat isolation key header value. Required. - :vartype chat_isolation_key: str + :ivar type: The type of insights request. Required. Insights on an Evaluation run result. + :vartype type: str or ~azure.ai.projects.models.EVALUATION_RUN_CLUSTER_INSIGHT + :ivar eval_id: Evaluation Id for the insights. Required. + :vartype eval_id: str + :ivar run_ids: List of evaluation run IDs for the insights. Required. + :vartype run_ids: list[str] + :ivar model_configuration: Configuration of the model used in the insight generation. + :vartype model_configuration: ~azure.ai.projects.models.InsightModelConfiguration """ - kind: Literal[IsolationKeySourceKind.HEADER] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. HEADER.""" - user_isolation_key: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The user isolation key header value. Required.""" - chat_isolation_key: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The chat isolation key header value. Required.""" + type: Literal[InsightType.EVALUATION_RUN_CLUSTER_INSIGHT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of insights request. Required. Insights on an Evaluation run result.""" + eval_id: str = rest_field(name="evalId", visibility=["read", "create", "update", "delete", "query"]) + """Evaluation Id for the insights. Required.""" + run_ids: list[str] = rest_field(name="runIds", visibility=["read", "create", "update", "delete", "query"]) + """List of evaluation run IDs for the insights. Required.""" + model_configuration: Optional["_models.InsightModelConfiguration"] = rest_field( + name="modelConfiguration", visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration of the model used in the insight generation.""" @overload def __init__( self, *, - user_isolation_key: str, - chat_isolation_key: str, + eval_id: str, + run_ids: list[str], + model_configuration: Optional["_models.InsightModelConfiguration"] = None, ) -> None: ... @overload @@ -5543,28 +6202,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = IsolationKeySourceKind.HEADER # type: ignore - + self.type = InsightType.EVALUATION_RUN_CLUSTER_INSIGHT # type: ignore -class TelemetryEndpointAuth(_Model): - """Authentication configuration for a telemetry endpoint. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - HeaderTelemetryEndpointAuth +class EvaluationRunClusterInsightResult(InsightResult, discriminator="EvaluationRunClusterInsight"): + """Insights from the evaluation run cluster analysis. - :ivar type: The authentication type. Required. "header" - :vartype type: str or ~azure.ai.projects.models.TelemetryEndpointAuthType + :ivar type: The type of insights result. Required. Insights on an Evaluation run result. + :vartype type: str or ~azure.ai.projects.models.EVALUATION_RUN_CLUSTER_INSIGHT + :ivar cluster_insight: Required. + :vartype cluster_insight: ~azure.ai.projects.models.ClusterInsightResult """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The authentication type. Required. \"header\"""" + type: Literal[InsightType.EVALUATION_RUN_CLUSTER_INSIGHT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of insights result. Required. Insights on an Evaluation run result.""" + cluster_insight: "_models.ClusterInsightResult" = rest_field( + name="clusterInsight", visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" @overload def __init__( self, *, - type: str, + cluster_insight: "_models.ClusterInsightResult", ) -> None: ... @overload @@ -5576,40 +6237,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = InsightType.EVALUATION_RUN_CLUSTER_INSIGHT # type: ignore -class HeaderTelemetryEndpointAuth(TelemetryEndpointAuth, discriminator="header"): - """Header-based secret authentication for a telemetry endpoint. The resolved secret value is - injected as an HTTP header. +class ScheduleTask(_Model): + """Schedule task model. - :ivar type: The authentication type, always 'header' for header-based secret authentication. - Required. Header-based secret authentication. - :vartype type: str or ~azure.ai.projects.models.HEADER - :ivar header_name: The name of the HTTP header to inject the secret value into. Required. - :vartype header_name: str - :ivar secret_id: The identifier of the secret store or connection. Required. - :vartype secret_id: str - :ivar secret_key: The key within the secret to retrieve the authentication value. Required. - :vartype secret_key: str + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + EvaluationScheduleTask, InsightScheduleTask + + :ivar type: Type of the task. Required. Known values are: "Evaluation" and "Insight". + :vartype type: str or ~azure.ai.projects.models.ScheduleTaskType + :ivar configuration: Configuration for the task. + :vartype configuration: dict[str, str] """ - type: Literal[TelemetryEndpointAuthType.HEADER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The authentication type, always 'header' for header-based secret authentication. Required. - Header-based secret authentication.""" - header_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the HTTP header to inject the secret value into. Required.""" - secret_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The identifier of the secret store or connection. Required.""" - secret_key: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The key within the secret to retrieve the authentication value. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Type of the task. Required. Known values are: \"Evaluation\" and \"Insight\".""" + configuration: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Configuration for the task.""" @overload def __init__( self, *, - header_name: str, - secret_id: str, - secret_key: str, + type: str, + configuration: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -5621,99 +6275,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TelemetryEndpointAuthType.HEADER # type: ignore -class HostedAgentDefinition(AgentDefinition, discriminator="hosted"): - """The hosted agent definition. +class EvaluationScheduleTask(ScheduleTask, discriminator="Evaluation"): + """Evaluation task for the schedule. - :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. - :vartype rai_config: ~azure.ai.projects.models.RaiConfig - :ivar kind: Required. HOSTED. - :vartype kind: str or ~azure.ai.projects.models.HOSTED - :ivar tools: An array of tools the hosted agent's model may call while generating a response. - You can specify which tool to use by setting the ``tool_choice`` parameter. - :vartype tools: list[~azure.ai.projects.models.Tool] - :ivar container_protocol_versions: The protocols that the agent supports for ingress - communication of the containers. - :vartype container_protocol_versions: list[~azure.ai.projects.models.ProtocolVersionRecord] - :ivar cpu: The CPU configuration for the hosted agent. Required. - :vartype cpu: str - :ivar memory: The memory configuration for the hosted agent. Required. - :vartype memory: str - :ivar environment_variables: Environment variables to set in the hosted agent container. - :vartype environment_variables: dict[str, str] - :ivar image: The image ID for the agent, applicable to image-based hosted agents. - :vartype image: str - :ivar container_configuration: Container-based deployment configuration. Provide this for - image-based deployments. Mutually exclusive with code_configuration — the service validates - that exactly one is set. - :vartype container_configuration: ~azure.ai.projects.models.ContainerConfiguration - :ivar protocol_versions: The protocols that the agent supports for ingress communication. - :vartype protocol_versions: list[~azure.ai.projects.models.ProtocolVersionRecord] - :ivar code_configuration: Code-based deployment configuration. Provide this for code-based - deployments. Mutually exclusive with container_configuration — the service validates that - exactly one is set. - :vartype code_configuration: ~azure.ai.projects.models.CodeConfiguration - :ivar telemetry_config: Optional customer-supplied telemetry configuration for exporting - container logs, traces, and metrics. - :vartype telemetry_config: ~azure.ai.projects.models.TelemetryConfig + :ivar configuration: Configuration for the task. + :vartype configuration: dict[str, str] + :ivar type: Required. Evaluation task. + :vartype type: str or ~azure.ai.projects.models.EVALUATION + :ivar eval_id: Identifier of the evaluation group. Required. + :vartype eval_id: str + :ivar eval_run: The evaluation run payload. Required. + :vartype eval_run: any """ - kind: Literal[AgentKind.HOSTED] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. HOSTED.""" - tools: Optional[list["_models.Tool"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An array of tools the hosted agent's model may call while generating a response. You can - specify which tool to use by setting the ``tool_choice`` parameter.""" - container_protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The protocols that the agent supports for ingress communication of the containers.""" - cpu: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The CPU configuration for the hosted agent. Required.""" - memory: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The memory configuration for the hosted agent. Required.""" - environment_variables: Optional[dict[str, str]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Environment variables to set in the hosted agent container.""" - image: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The image ID for the agent, applicable to image-based hosted agents.""" - container_configuration: Optional["_models.ContainerConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Container-based deployment configuration. Provide this for image-based deployments. Mutually - exclusive with code_configuration — the service validates that exactly one is set.""" - protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The protocols that the agent supports for ingress communication.""" - code_configuration: Optional["_models.CodeConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Code-based deployment configuration. Provide this for code-based deployments. Mutually - exclusive with container_configuration — the service validates that exactly one is set.""" - telemetry_config: Optional["_models.TelemetryConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional customer-supplied telemetry configuration for exporting container logs, traces, and - metrics.""" + 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, *, - cpu: str, - memory: str, - rai_config: Optional["_models.RaiConfig"] = None, - tools: Optional[list["_models.Tool"]] = None, - container_protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = None, - environment_variables: Optional[dict[str, str]] = None, - image: Optional[str] = None, - container_configuration: Optional["_models.ContainerConfiguration"] = None, - protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = None, - code_configuration: Optional["_models.CodeConfiguration"] = None, - telemetry_config: Optional["_models.TelemetryConfig"] = None, + eval_id: str, + eval_run: Any, + configuration: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -5725,22 +6315,60 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = AgentKind.HOSTED # type: ignore + self.type = ScheduleTaskType.EVALUATION # type: ignore -class HourlyRecurrenceSchedule(RecurrenceSchedule, discriminator="Hourly"): - """Hourly recurrence schedule. +class EvaluationTaxonomy(_Model): + """Evaluation Taxonomy Definition. - :ivar type: Required. Hourly recurrence pattern. - :vartype type: str or ~azure.ai.projects.models.HOURLY + :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] """ - type: Literal[RecurrenceType.HOURLY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Hourly recurrence pattern.""" + 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, + *, + 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 @@ -5752,28 +6380,25 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RecurrenceType.HOURLY # type: ignore -class HumanEvaluationPreviewRuleAction(EvaluationRuleAction, discriminator="humanEvaluationPreview"): - """Evaluation rule action for human evaluation. +class EvaluatorCredentialRequest(_Model): + """Request body for getting evaluator credentials. - :ivar type: Required. Human evaluation preview. - :vartype type: str or ~azure.ai.projects.models.HUMAN_EVALUATION_PREVIEW - :ivar template_id: Human evaluation template Id. Required. - :vartype template_id: str + :ivar blob_uri: The blob URI for the evaluator storage. Example: + ``https://account.blob.core.windows.net:443/container``. Required. + :vartype blob_uri: str """ - type: Literal[EvaluationRuleActionType.HUMAN_EVALUATION_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Human evaluation preview.""" - template_id: str = rest_field(name="templateId", visibility=["read", "create", "update", "delete", "query"]) - """Human evaluation template Id. Required.""" + blob_uri: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The blob URI for the evaluator storage. Example: + ``https://account.blob.core.windows.net:443/container``. Required.""" @overload def __init__( self, *, - template_id: str, + blob_uri: str, ) -> None: ... @overload @@ -5785,29 +6410,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluationRuleActionType.HUMAN_EVALUATION_PREVIEW # type: ignore -class HybridSearchOptions(_Model): - """HybridSearchOptions. +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 embedding_weight: The weight of the embedding in the reciprocal ranking fusion. Required. - :vartype embedding_weight: int - :ivar text_weight: The weight of the text in the reciprocal ranking fusion. Required. - :vartype text_weight: int + :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] """ - embedding_weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The weight of the embedding in the reciprocal ranking fusion. Required.""" - text_weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The weight of the text in the reciprocal ranking fusion. 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, *, - embedding_weight: int, - text_weight: int, + dataset: "_models.DatasetReference", + kinds: list[str], ) -> None: ... @overload @@ -5821,130 +6461,238 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ImageGenTool(Tool, discriminator="image_generation"): - """Image generation tool. - - :ivar type: The type of the image generation tool. Always ``image_generation``. Required. - IMAGE_GENERATION. - :vartype type: str or ~azure.ai.projects.models.IMAGE_GENERATION - :ivar model: Is one of the following types: Literal["gpt-image-1"], - Literal["gpt-image-1-mini"], Literal["gpt-image-1.5"], str - :vartype model: str or str or str or str - :ivar quality: The quality of the generated image. One of ``low``, ``medium``, ``high``, or - ``auto``. Default: ``auto``. Is one of the following types: Literal["low"], Literal["medium"], - Literal["high"], Literal["auto"] - :vartype quality: str or str or str or str - :ivar size: The size of the generated image. One of ``1024x1024``, ``1024x1536``, - ``1536x1024``, or ``auto``. Default: ``auto``. Is one of the following types: - Literal["1024x1024"], Literal["1024x1536"], Literal["1536x1024"], Literal["auto"] - :vartype size: str or str or str or str - :ivar output_format: The output format of the generated image. One of ``png``, ``webp``, or - ``jpeg``. Default: ``png``. Is one of the following types: Literal["png"], Literal["webp"], - Literal["jpeg"] - :vartype output_format: str or str or str - :ivar output_compression: Compression level for the output image. Default: 100. - :vartype output_compression: int - :ivar moderation: Moderation level for the generated image. Default: ``auto``. Is either a - Literal["auto"] type or a Literal["low"] type. - :vartype moderation: str or str - :ivar background: Background type for the generated image. One of ``transparent``, ``opaque``, - or ``auto``. Default: ``auto``. Is one of the following types: Literal["transparent"], - Literal["opaque"], Literal["auto"] - :vartype background: str or str or str - :ivar input_fidelity: Known values are: "high" and "low". - :vartype input_fidelity: str or ~azure.ai.projects.models.InputFidelity - :ivar input_image_mask: Optional mask for inpainting. Contains ``image_url`` (string, optional) - and ``file_id`` (string, optional). - :vartype input_image_mask: ~azure.ai.projects.models.ImageGenToolInputImageMask - :ivar partial_images: Number of partial images to generate in streaming mode, from 0 (default - value) to 3. - :vartype partial_images: int - :ivar action: Whether to generate a new image or edit an existing image. Default: ``auto``. - Known values are: "generate", "edit", and "auto". - :vartype action: str or ~azure.ai.projects.models.ImageGenAction - :ivar name: Optional user-defined name for this tool or configuration. - :vartype name: str - :ivar description: Optional user-defined description for this tool or configuration. - :vartype description: str - """ +class EvaluatorGenerationInputs(_Model): + """Caller-supplied inputs for an evaluator generation job. - type: Literal[ToolType.IMAGE_GENERATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the image generation tool. Always ``image_generation``. Required. IMAGE_GENERATION.""" - model: Optional[Union[Literal["gpt-image-1"], Literal["gpt-image-1-mini"], Literal["gpt-image-1.5"], str]] = ( - rest_field(visibility=["read", "create", "update", "delete", "query"]) - ) - """Is one of the following types: Literal[\"gpt-image-1\"], Literal[\"gpt-image-1-mini\"], - Literal[\"gpt-image-1.5\"], str""" - quality: Optional[Literal["low", "medium", "high", "auto"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The quality of the generated image. One of ``low``, ``medium``, ``high``, or ``auto``. Default: - ``auto``. Is one of the following types: Literal[\"low\"], Literal[\"medium\"], - Literal[\"high\"], Literal[\"auto\"]""" - size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The size of the generated image. One of ``1024x1024``, ``1024x1536``, ``1536x1024``, or - ``auto``. Default: ``auto``. Is one of the following types: Literal[\"1024x1024\"], - Literal[\"1024x1536\"], Literal[\"1536x1024\"], Literal[\"auto\"]""" - output_format: Optional[Literal["png", "webp", "jpeg"]] = rest_field( + :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 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 (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 + """ + + sources: list["_models.EvaluatorGenerationJobSource"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The output format of the generated image. One of ``png``, ``webp``, or ``jpeg``. Default: - ``png``. Is one of the following types: Literal[\"png\"], Literal[\"webp\"], Literal[\"jpeg\"]""" - output_compression: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Compression level for the output image. Default: 100.""" - moderation: Optional[Literal["auto", "low"]] = rest_field( + """Source materials for generation — agent descriptions, prompts, traces, or datasets. Each entry + is an ``EvaluatorGenerationJobSource`` variant discriminated by ``type``. Required.""" + 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 (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, + *, + sources: list["_models.EvaluatorGenerationJobSource"], + model: str, + evaluator_name: str, + evaluator_display_name: Optional[str] = None, + evaluator_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 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 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 + """ + + id: str = rest_field(visibility=["read"]) + """Server-assigned unique identifier. Required.""" + inputs: Optional["_models.EvaluatorGenerationInputs"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Moderation level for the generated image. Default: ``auto``. Is either a Literal[\"auto\"] type - or a Literal[\"low\"] type.""" - background: Optional[Literal["transparent", "opaque", "auto"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Background type for the generated image. One of ``transparent``, ``opaque``, or ``auto``. - Default: ``auto``. Is one of the following types: Literal[\"transparent\"], - Literal[\"opaque\"], Literal[\"auto\"]""" - input_fidelity: Optional[Union[str, "_models.InputFidelity"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Known values are: \"high\" and \"low\".""" - input_image_mask: Optional["_models.ImageGenToolInputImageMask"] = rest_field( + """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, + *, + inputs: Optional["_models.EvaluatorGenerationInputs"] = 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 EvaluatorGenerationTokenUsage(_Model): + """Token consumption summary for an evaluator generation job. Populated when the job reaches a + terminal state. + + :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 + """ + + 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, + *, + input_tokens: int, + output_tokens: int, + total_tokens: int, + ) -> 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 EvaluatorMetric(_Model): + """Evaluator Metric. + + :ivar type: Type of the metric. Known values are: "ordinal", "continuous", and "boolean". + :vartype type: str or ~azure.ai.projects.models.EvaluatorMetricType + :ivar desirable_direction: It indicates whether a higher value is better or a lower value is + better for this metric. Known values are: "increase", "decrease", and "neutral". + :vartype desirable_direction: str or ~azure.ai.projects.models.EvaluatorMetricDirection + :ivar min_value: Minimum value for the metric. + :vartype min_value: float + :ivar max_value: Maximum value for the metric. If not specified, it is assumed to be unbounded. + :vartype max_value: float + :ivar threshold: Default pass/fail threshold for this metric. + :vartype threshold: float + :ivar is_primary: Indicates if this metric is primary when there are multiple metrics. + :vartype is_primary: bool + """ + + type: Optional[Union[str, "_models.EvaluatorMetricType"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Optional mask for inpainting. Contains ``image_url`` (string, optional) and ``file_id`` - (string, optional).""" - partial_images: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of partial images to generate in streaming mode, from 0 (default value) to 3.""" - action: Optional[Union[str, "_models.ImageGenAction"]] = rest_field( + """Type of the metric. Known values are: \"ordinal\", \"continuous\", and \"boolean\".""" + desirable_direction: Optional[Union[str, "_models.EvaluatorMetricDirection"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Whether to generate a new image or edit an existing image. Default: ``auto``. Known values are: - \"generate\", \"edit\", and \"auto\".""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined name for this tool or configuration.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined description for this tool or configuration.""" + """It indicates whether a higher value is better or a lower value is better for this metric. Known + values are: \"increase\", \"decrease\", and \"neutral\".""" + min_value: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Minimum value for the metric.""" + max_value: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum value for the metric. If not specified, it is assumed to be unbounded.""" + threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Default pass/fail threshold for this metric.""" + is_primary: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Indicates if this metric is primary when there are multiple metrics.""" @overload def __init__( self, *, - model: Optional[ - Union[Literal["gpt-image-1"], Literal["gpt-image-1-mini"], Literal["gpt-image-1.5"], str] - ] = None, - quality: Optional[Literal["low", "medium", "high", "auto"]] = None, - size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = None, - output_format: Optional[Literal["png", "webp", "jpeg"]] = None, - output_compression: Optional[int] = None, - moderation: Optional[Literal["auto", "low"]] = None, - background: Optional[Literal["transparent", "opaque", "auto"]] = None, - input_fidelity: Optional[Union[str, "_models.InputFidelity"]] = None, - input_image_mask: Optional["_models.ImageGenToolInputImageMask"] = None, - partial_images: Optional[int] = None, - action: Optional[Union[str, "_models.ImageGenAction"]] = None, - name: Optional[str] = None, - description: Optional[str] = None, + type: Optional[Union[str, "_models.EvaluatorMetricType"]] = None, + desirable_direction: Optional[Union[str, "_models.EvaluatorMetricDirection"]] = None, + min_value: Optional[float] = None, + max_value: Optional[float] = None, + threshold: Optional[float] = None, + is_primary: Optional[bool] = None, ) -> None: ... @overload @@ -5956,27 +6704,90 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.IMAGE_GENERATION # type: ignore -class ImageGenToolInputImageMask(_Model): - """ImageGenToolInputImageMask. +class EvaluatorVersion(_Model): + """Evaluator Definition. - :ivar image_url: - :vartype image_url: str - :ivar file_id: - :vartype file_id: str + :ivar display_name: Display Name for evaluator. It helps to find the evaluator easily in AI + Foundry. It does not need to be unique. + :vartype display_name: str + :ivar metadata: Metadata about the evaluator. + :vartype metadata: dict[str, str] + :ivar evaluator_type: The type of the evaluator. Required. Known values are: "builtin" and + "custom". + :vartype evaluator_type: str or ~azure.ai.projects.models.EvaluatorType + :ivar categories: The categories of the evaluator. Required. + :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. + :vartype created_at: ~datetime.datetime + :ivar modified_at: Last modified date/time of the evaluator. Required. + :vartype modified_at: ~datetime.datetime + :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] """ - image_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - file_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + display_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Display Name for evaluator. It helps to find the evaluator easily in AI Foundry. It does not + need to be unique.""" + metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Metadata about the evaluator.""" + evaluator_type: Union[str, "_models.EvaluatorType"] = rest_field(visibility=["read", "create"]) + """The type of the evaluator. Required. Known values are: \"builtin\" and \"custom\".""" + categories: list[Union[str, "_models.EvaluatorCategory"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """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") + """Creation date/time of the evaluator. Required.""" + modified_at: datetime.datetime = rest_field(visibility=["read"], format="rfc3339") + """Last modified date/time of the evaluator. 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.""" @overload def __init__( self, *, - image_url: Optional[str] = None, - file_id: Optional[str] = None, + evaluator_type: Union[str, "_models.EvaluatorType"], + categories: list[Union[str, "_models.EvaluatorCategory"]], + definition: "_models.EvaluatorDefinition", + display_name: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -5990,35 +6801,40 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InlineSkillParam(ContainerSkill, discriminator="inline"): - """InlineSkillParam. +class ExternalAgentDefinition(AgentDefinition, discriminator="external"): + """The external agent definition. Represents a third-party agent hosted outside Foundry (for + example, on GCP or AWS). Registration is metadata-only: Foundry records the agent definition to + light up observability experiences (traces, evaluations) over customer-emitted OpenTelemetry + data. - :ivar type: Defines an inline skill for this request. Required. INLINE. - :vartype type: str or ~azure.ai.projects.models.INLINE - :ivar name: The name of the skill. Required. - :vartype name: str - :ivar description: The description of the skill. Required. - :vartype description: str - :ivar source: Inline skill payload. Required. - :vartype source: ~azure.ai.projects.models.InlineSkillSourceParam + :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. + :vartype rai_config: ~azure.ai.projects.models.RaiConfig + :ivar kind: Required. EXTERNAL. + :vartype kind: str or ~azure.ai.projects.models.EXTERNAL + :ivar otel_agent_id: The OpenTelemetry agent identifier used to attribute customer-emitted + spans to this Foundry agent. Spans must include the attribute ``gen_ai.agent.id = + `` to appear under this registration. Defaults to the top-level agent name when + omitted. Provide an explicit value only for migration scenarios where the running external + agent already emits a stable id that differs from the Foundry agent name. The resolved value is + always echoed on read. + :vartype otel_agent_id: str """ - type: Literal[ContainerSkillType.INLINE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Defines an inline skill for this request. Required. INLINE.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the skill. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The description of the skill. Required.""" - source: "_models.InlineSkillSourceParam" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Inline skill payload. Required.""" + kind: Literal[AgentKind.EXTERNAL] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. EXTERNAL.""" + otel_agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The OpenTelemetry agent identifier used to attribute customer-emitted spans to this Foundry + agent. Spans must include the attribute ``gen_ai.agent.id = `` to appear under + this registration. Defaults to the top-level agent name when omitted. Provide an explicit value + only for migration scenarios where the running external agent already emits a stable id that + differs from the Foundry agent name. The resolved value is always echoed on read.""" @overload def __init__( self, *, - name: str, - description: str, - source: "_models.InlineSkillSourceParam", + rai_config: Optional["_models.RaiConfig"] = None, + otel_agent_id: Optional[str] = None, ) -> None: ... @overload @@ -6030,35 +6846,2204 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ContainerSkillType.INLINE # type: ignore + self.kind = AgentKind.EXTERNAL # type: ignore -class InlineSkillSourceParam(_Model): - """Inline skill payload. +class FabricDataAgentToolParameters(_Model): + """The fabric data agent tool parameters. - :ivar type: The type of the inline skill source. Must be ``base64``. Required. Default value is - "base64". - :vartype type: str - :ivar media_type: The media type of the inline skill payload. Must be ``application/zip``. - Required. Default value is "application/zip". - :vartype media_type: str - :ivar data: Base64-encoded skill zip bundle. Required. - :vartype data: str + :ivar project_connections: The project connections attached to this tool. There can be a + maximum of 1 connection resource attached to the tool. + :vartype project_connections: list[~azure.ai.projects.models.ToolProjectConnection] """ - type: Literal["base64"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The type of the inline skill source. Must be ``base64``. Required. Default value is \"base64\".""" - media_type: Literal["application/zip"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The media type of the inline skill payload. Must be ``application/zip``. Required. Default - value is \"application/zip\".""" - data: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Base64-encoded skill zip bundle. Required.""" + project_connections: Optional[list["_models.ToolProjectConnection"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The project connections attached to this tool. There can be a maximum of 1 connection resource + attached to the tool.""" @overload def __init__( self, *, - data: str, + project_connections: Optional[list["_models.ToolProjectConnection"]] = 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 FabricIQPreviewTool(Tool, discriminator="fabric_iq_preview"): + """A FabricIQ server-side tool. + + :ivar type: The object type, which is always 'fabric_iq_preview'. Required. FABRIC_IQ_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.FABRIC_IQ_PREVIEW + :ivar project_connection_id: The ID of the FabricIQ project connection. Required. + :vartype project_connection_id: str + :ivar server_label: (Optional) The label of the FabricIQ MCP server to connect to. + :vartype server_label: str + :ivar server_url: (Optional) The URL of the FabricIQ MCP server. If not provided, the URL from + the project connection will be used. + :vartype server_url: str + :ivar require_approval: (Optional) Whether the agent requires approval before executing + actions. Default is always. Is either a MCPToolRequireApproval type or a str type. + :vartype require_approval: ~azure.ai.projects.models.MCPToolRequireApproval or str + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.FABRIC_IQ_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The object type, which is always 'fabric_iq_preview'. Required. FABRIC_IQ_PREVIEW.""" + project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the FabricIQ project connection. Required.""" + server_label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """(Optional) The label of the FabricIQ MCP server to connect to.""" + server_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """(Optional) The URL of the FabricIQ MCP server. If not provided, the URL from the project + connection will be used.""" + require_approval: Optional[Union["_models.MCPToolRequireApproval", str]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """(Optional) Whether the agent requires approval before executing actions. Default is always. Is + either a MCPToolRequireApproval type or a str type.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + project_connection_id: str, + 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, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = 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, + ) -> 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. + + :ivar data_uri: URI of the data (`example `_). + Required. + :vartype data_uri: str + :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 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 type: Dataset type. Required. URI file. + :vartype type: str or ~azure.ai.projects.models.URI_FILE + """ + + type: Literal[DatasetType.URI_FILE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Dataset type. Required. URI file.""" + + @overload + def __init__( + self, + *, + data_uri: 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) + self.type = DatasetType.URI_FILE # type: ignore + + +class FileSearchTool(Tool, discriminator="file_search"): + """File search. + + :ivar type: The type of the file search tool. Always ``file_search``. Required. FILE_SEARCH. + :vartype type: str or ~azure.ai.projects.models.FILE_SEARCH + :ivar vector_store_ids: The IDs of the vector stores to search. Required. + :vartype vector_store_ids: list[str] + :ivar max_num_results: The maximum number of results to return. This number should be between 1 + and 50 inclusive. + :vartype max_num_results: int + :ivar ranking_options: Ranking options for search. + :vartype ranking_options: ~azure.ai.projects.models.RankingOptions + :ivar filters: Is either a ComparisonFilter type or a CompoundFilter type. + :vartype filters: ~azure.ai.projects.models.ComparisonFilter or + ~azure.ai.projects.models.CompoundFilter + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.FILE_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the file search tool. Always ``file_search``. Required. FILE_SEARCH.""" + vector_store_ids: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The IDs of the vector stores to search. Required.""" + max_num_results: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The maximum number of results to return. This number should be between 1 and 50 inclusive.""" + ranking_options: Optional["_models.RankingOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Ranking options for search.""" + filters: Optional["_types.Filters"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Is either a ComparisonFilter type or a CompoundFilter type.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + vector_store_ids: list[str], + max_num_results: Optional[int] = None, + ranking_options: Optional["_models.RankingOptions"] = None, + filters: Optional["_types.Filters"] = None, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = 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.FILE_SEARCH # type: ignore + + +class VersionSelectionRule(_Model): + """VersionSelectionRule. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + FixedRatioVersionSelectionRule + + :ivar type: Required. "FixedRatio" + :vartype type: str or ~azure.ai.projects.models.VersionSelectorType + :ivar agent_version: The agent version to route traffic to. Required. + :vartype agent_version: str + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. \"FixedRatio\"""" + agent_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent version to route traffic to. Required.""" + + @overload + def __init__( + self, + *, + type: str, + agent_version: 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 FixedRatioVersionSelectionRule(VersionSelectionRule, discriminator="FixedRatio"): + """FixedRatioVersionSelectionRule. + + :ivar agent_version: The agent version to route traffic to. Required. + :vartype agent_version: str + :ivar type: Required. FIXED_RATIO. + :vartype type: str or ~azure.ai.projects.models.FIXED_RATIO + :ivar traffic_percentage: The percentage of traffic to route to the version. Must be between 0 + and 100. Required. + :vartype traffic_percentage: int + """ + + type: Literal[VersionSelectorType.FIXED_RATIO] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. FIXED_RATIO.""" + traffic_percentage: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The percentage of traffic to route to the version. Must be between 0 and 100. Required.""" + + @overload + def __init__( + self, + *, + agent_version: str, + traffic_percentage: int, + ) -> 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 = VersionSelectorType.FIXED_RATIO # type: ignore + + +class FolderDatasetVersion(DatasetVersion, discriminator="uri_folder"): + """FileDatasetVersion Definition. + + :ivar data_uri: URI of the data (`example `_). + Required. + :vartype data_uri: str + :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 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 type: Dataset type. Required. URI folder. + :vartype type: str or ~azure.ai.projects.models.URI_FOLDER + """ + + type: Literal[DatasetType.URI_FOLDER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Dataset type. Required. URI folder.""" + + @overload + def __init__( + self, + *, + data_uri: 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) + 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. + + :ivar type: The type of the shell tool. Always ``shell``. Required. SHELL. + :vartype type: str or ~azure.ai.projects.models.SHELL + :ivar environment: + :vartype environment: ~azure.ai.projects.models.FunctionShellToolParamEnvironment + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the shell tool. Always ``shell``. Required. SHELL.""" + environment: Optional["_models.FunctionShellToolParamEnvironment"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + environment: Optional["_models.FunctionShellToolParamEnvironment"] = None, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = 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.SHELL # type: ignore + + +class FunctionShellToolParamEnvironmentContainerReferenceParam( + FunctionShellToolParamEnvironment, discriminator="container_reference" +): # pylint: disable=name-too-long + """FunctionShellToolParamEnvironmentContainerReferenceParam. + + :ivar type: References a container created with the /v1/containers endpoint. Required. + CONTAINER_REFERENCE. + :vartype type: str or ~azure.ai.projects.models.CONTAINER_REFERENCE + :ivar container_id: The ID of the referenced container. Required. + :vartype container_id: str + """ + + type: Literal[FunctionShellToolParamEnvironmentType.CONTAINER_REFERENCE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """References a container created with the /v1/containers endpoint. Required. CONTAINER_REFERENCE.""" + container_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the referenced container. Required.""" + + @overload + def __init__( + self, + *, + container_id: 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 = FunctionShellToolParamEnvironmentType.CONTAINER_REFERENCE # type: ignore + + +class FunctionShellToolParamEnvironmentLocalEnvironmentParam( + FunctionShellToolParamEnvironment, discriminator="local" +): # pylint: disable=name-too-long + """FunctionShellToolParamEnvironmentLocalEnvironmentParam. + + :ivar type: Use a local computer environment. Required. LOCAL. + :vartype type: str or ~azure.ai.projects.models.LOCAL + :ivar skills: An optional list of skills. + :vartype skills: list[~azure.ai.projects.models.LocalSkillParam] + """ + + type: Literal[FunctionShellToolParamEnvironmentType.LOCAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Use a local computer environment. Required. LOCAL.""" + skills: Optional[list["_models.LocalSkillParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """An optional list of skills.""" + + @overload + def __init__( + self, + *, + skills: Optional[list["_models.LocalSkillParam"]] = 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 = FunctionShellToolParamEnvironmentType.LOCAL # type: ignore + + +class FunctionTool(Tool, discriminator="function"): + """Function. + + :ivar type: The type of the function tool. Always ``function``. Required. FUNCTION. + :vartype type: str or ~azure.ai.projects.models.FUNCTION + :ivar name: The name of the function to call. Required. + :vartype name: str + :ivar description: + :vartype description: str + :ivar parameters: Required. + :vartype parameters: dict[str, any] + :ivar strict: Required. + :vartype strict: bool + """ + + type: Literal[ToolType.FUNCTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the function tool. Always ``function``. Required. FUNCTION.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function to call. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + parameters: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + strict: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + name: str, + parameters: dict[str, Any], + strict: bool, + 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.FUNCTION # type: ignore + + +class RoutineTrigger(_Model): + """Base model for a routine trigger. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + GitHubIssueOpenedRoutineTrigger, ScheduleRoutineTrigger, TimerRoutineTrigger + + :ivar type: The trigger type. Required. Known values are: "github_issue_opened", "schedule", + and "timer". + :vartype type: str or ~azure.ai.projects.models.RoutineTriggerType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The trigger type. Required. Known values are: \"github_issue_opened\", \"schedule\", and + \"timer\".""" + + @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 GitHubIssueOpenedRoutineTrigger(RoutineTrigger, discriminator="github_issue_opened"): + """A GitHub issue-opened routine trigger. + + :ivar type: The trigger type. Required. A GitHub issue-opened trigger. + :vartype type: str or ~azure.ai.projects.models.GITHUB_ISSUE_OPENED + :ivar connection_id: The workspace connection identifier that resolves the GitHub configuration + for the trigger. Required. + :vartype connection_id: str + :ivar assignee: The GitHub assignee or organization filter that scopes which issues can fire + the trigger. Required. + :vartype assignee: str + :ivar repository: The GitHub repository filter that scopes which issues can fire the trigger. + Required. + :vartype repository: str + """ + + type: Literal[RoutineTriggerType.GITHUB_ISSUE_OPENED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The trigger type. Required. A GitHub issue-opened trigger.""" + connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The workspace connection identifier that resolves the GitHub configuration for the trigger. + Required.""" + assignee: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The GitHub assignee or organization filter that scopes which issues can fire the trigger. + Required.""" + repository: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The GitHub repository filter that scopes which issues can fire the trigger. Required.""" + + @overload + def __init__( + self, + *, + connection_id: str, + assignee: str, + repository: 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 = RoutineTriggerType.GITHUB_ISSUE_OPENED # type: ignore + + +class HeaderIsolationKeySource(IsolationKeySource, discriminator="Header"): + """HeaderIsolationKeySource. + + :ivar kind: Required. HEADER. + :vartype kind: str or ~azure.ai.projects.models.HEADER + """ + + kind: Literal[IsolationKeySourceKind.HEADER] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. HEADER.""" + + @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.kind = IsolationKeySourceKind.HEADER # type: ignore + + +class TelemetryEndpointAuth(_Model): + """Authentication configuration for a telemetry endpoint. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + HeaderTelemetryEndpointAuth + + :ivar type: The authentication type. Required. "header" + :vartype type: str or ~azure.ai.projects.models.TelemetryEndpointAuthType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The authentication type. Required. \"header\"""" + + @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 HeaderTelemetryEndpointAuth(TelemetryEndpointAuth, discriminator="header"): + """Header-based secret authentication for a telemetry endpoint. The resolved secret value is + injected as an HTTP header. + + :ivar type: The authentication type, always 'header' for header-based secret authentication. + Required. Header-based secret authentication. + :vartype type: str or ~azure.ai.projects.models.HEADER + :ivar header_name: The name of the HTTP header to inject the secret value into. Required. + :vartype header_name: str + :ivar secret_id: The identifier of the secret store or connection. Required. + :vartype secret_id: str + :ivar secret_key: The key within the secret to retrieve the authentication value. Required. + :vartype secret_key: str + """ + + type: Literal[TelemetryEndpointAuthType.HEADER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The authentication type, always 'header' for header-based secret authentication. Required. + Header-based secret authentication.""" + header_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the HTTP header to inject the secret value into. Required.""" + secret_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The identifier of the secret store or connection. Required.""" + secret_key: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The key within the secret to retrieve the authentication value. Required.""" + + @overload + def __init__( + self, + *, + header_name: str, + secret_id: str, + secret_key: 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 = TelemetryEndpointAuthType.HEADER # type: ignore + + +class HostedAgentDefinition(AgentDefinition, discriminator="hosted"): + """The hosted agent definition. + + :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. + :vartype rai_config: ~azure.ai.projects.models.RaiConfig + :ivar kind: Required. HOSTED. + :vartype kind: str or ~azure.ai.projects.models.HOSTED + :ivar tools: An array of tools the hosted agent's model may call while generating a response. + You can specify which tool to use by setting the ``tool_choice`` parameter. + :vartype tools: list[~azure.ai.projects.models.Tool] + :ivar container_protocol_versions: The protocols that the agent supports for ingress + communication of the containers. + :vartype container_protocol_versions: list[~azure.ai.projects.models.ProtocolVersionRecord] + :ivar cpu: The CPU configuration for the hosted agent. Required. + :vartype cpu: str + :ivar memory: The memory configuration for the hosted agent. Required. + :vartype memory: str + :ivar environment_variables: Environment variables to set in the hosted agent container. + :vartype environment_variables: dict[str, str] + :ivar image: The image ID for the agent, applicable to image-based hosted agents. + :vartype image: str + :ivar container_configuration: Container-based deployment configuration. Provide this for + image-based deployments. Mutually exclusive with code_configuration — the service validates + that exactly one is set. + :vartype container_configuration: ~azure.ai.projects.models.ContainerConfiguration + :ivar protocol_versions: The protocols that the agent supports for ingress communication. + :vartype protocol_versions: list[~azure.ai.projects.models.ProtocolVersionRecord] + :ivar code_configuration: Code-based deployment configuration. Provide this for code-based + deployments. Mutually exclusive with container_configuration — the service validates that + exactly one is set. + :vartype code_configuration: ~azure.ai.projects.models.CodeConfiguration + :ivar telemetry_config: Optional customer-supplied telemetry configuration for exporting + container logs, traces, and metrics. + :vartype telemetry_config: ~azure.ai.projects.models.TelemetryConfig + """ + + kind: Literal[AgentKind.HOSTED] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. HOSTED.""" + tools: Optional[list["_models.Tool"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An array of tools the hosted agent's model may call while generating a response. You can + specify which tool to use by setting the ``tool_choice`` parameter.""" + container_protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The protocols that the agent supports for ingress communication of the containers.""" + cpu: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The CPU configuration for the hosted agent. Required.""" + memory: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The memory configuration for the hosted agent. Required.""" + environment_variables: Optional[dict[str, str]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Environment variables to set in the hosted agent container.""" + image: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The image ID for the agent, applicable to image-based hosted agents.""" + container_configuration: Optional["_models.ContainerConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Container-based deployment configuration. Provide this for image-based deployments. Mutually + exclusive with code_configuration — the service validates that exactly one is set.""" + protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The protocols that the agent supports for ingress communication.""" + code_configuration: Optional["_models.CodeConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Code-based deployment configuration. Provide this for code-based deployments. Mutually + exclusive with container_configuration — the service validates that exactly one is set.""" + telemetry_config: Optional["_models.TelemetryConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional customer-supplied telemetry configuration for exporting container logs, traces, and + metrics.""" + + @overload + def __init__( + self, + *, + cpu: str, + memory: str, + rai_config: Optional["_models.RaiConfig"] = None, + tools: Optional[list["_models.Tool"]] = None, + container_protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = None, + environment_variables: Optional[dict[str, str]] = None, + image: Optional[str] = None, + container_configuration: Optional["_models.ContainerConfiguration"] = None, + protocol_versions: Optional[list["_models.ProtocolVersionRecord"]] = None, + code_configuration: Optional["_models.CodeConfiguration"] = None, + telemetry_config: Optional["_models.TelemetryConfig"] = 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.kind = AgentKind.HOSTED # type: ignore + + +class HourlyRecurrenceSchedule(RecurrenceSchedule, discriminator="Hourly"): + """Hourly recurrence schedule. + + :ivar type: Required. Hourly recurrence pattern. + :vartype type: str or ~azure.ai.projects.models.HOURLY + """ + + type: Literal[RecurrenceType.HOURLY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Hourly recurrence pattern.""" + + @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 = RecurrenceType.HOURLY # type: ignore + + +class HumanEvaluationPreviewRuleAction(EvaluationRuleAction, discriminator="humanEvaluationPreview"): + """Evaluation rule action for human evaluation. + + :ivar type: Required. Human evaluation preview. + :vartype type: str or ~azure.ai.projects.models.HUMAN_EVALUATION_PREVIEW + :ivar template_id: Human evaluation template Id. Required. + :vartype template_id: str + """ + + type: Literal[EvaluationRuleActionType.HUMAN_EVALUATION_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Human evaluation preview.""" + template_id: str = rest_field(name="templateId", visibility=["read", "create", "update", "delete", "query"]) + """Human evaluation template Id. Required.""" + + @overload + def __init__( + self, + *, + template_id: 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 = EvaluationRuleActionType.HUMAN_EVALUATION_PREVIEW # type: ignore + + +class HybridSearchOptions(_Model): + """HybridSearchOptions. + + :ivar embedding_weight: The weight of the embedding in the reciprocal ranking fusion. Required. + :vartype embedding_weight: int + :ivar text_weight: The weight of the text in the reciprocal ranking fusion. Required. + :vartype text_weight: int + """ + + embedding_weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The weight of the embedding in the reciprocal ranking fusion. Required.""" + text_weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The weight of the text in the reciprocal ranking fusion. Required.""" + + @overload + def __init__( + self, + *, + embedding_weight: int, + text_weight: int, + ) -> 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 ImageGenTool(Tool, discriminator="image_generation"): + """Image generation tool. + + :ivar type: The type of the image generation tool. Always ``image_generation``. Required. + IMAGE_GENERATION. + :vartype type: str or ~azure.ai.projects.models.IMAGE_GENERATION + :ivar model: Is one of the following types: Literal["gpt-image-1"], + Literal["gpt-image-1-mini"], Literal["gpt-image-1.5"], str + :vartype model: str or str or str or str + :ivar quality: The quality of the generated image. One of ``low``, ``medium``, ``high``, or + ``auto``. Default: ``auto``. Is one of the following types: Literal["low"], Literal["medium"], + Literal["high"], Literal["auto"] + :vartype quality: str or str or str or str + :ivar size: The size of the generated image. One of ``1024x1024``, ``1024x1536``, + ``1536x1024``, or ``auto``. Default: ``auto``. Is one of the following types: + Literal["1024x1024"], Literal["1024x1536"], Literal["1536x1024"], Literal["auto"] + :vartype size: str or str or str or str + :ivar output_format: The output format of the generated image. One of ``png``, ``webp``, or + ``jpeg``. Default: ``png``. Is one of the following types: Literal["png"], Literal["webp"], + Literal["jpeg"] + :vartype output_format: str or str or str + :ivar output_compression: Compression level for the output image. Default: 100. + :vartype output_compression: int + :ivar moderation: Moderation level for the generated image. Default: ``auto``. Is either a + Literal["auto"] type or a Literal["low"] type. + :vartype moderation: str or str + :ivar background: Background type for the generated image. One of ``transparent``, ``opaque``, + or ``auto``. Default: ``auto``. Is one of the following types: Literal["transparent"], + Literal["opaque"], Literal["auto"] + :vartype background: str or str or str + :ivar input_fidelity: Known values are: "high" and "low". + :vartype input_fidelity: str or ~azure.ai.projects.models.InputFidelity + :ivar input_image_mask: Optional mask for inpainting. Contains ``image_url`` (string, optional) + and ``file_id`` (string, optional). + :vartype input_image_mask: ~azure.ai.projects.models.ImageGenToolInputImageMask + :ivar partial_images: Number of partial images to generate in streaming mode, from 0 (default + value) to 3. + :vartype partial_images: int + :ivar action: Whether to generate a new image or edit an existing image. Default: ``auto``. + Known values are: "generate", "edit", and "auto". + :vartype action: str or ~azure.ai.projects.models.ImageGenAction + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.IMAGE_GENERATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the image generation tool. Always ``image_generation``. Required. IMAGE_GENERATION.""" + model: Optional[Union[Literal["gpt-image-1"], Literal["gpt-image-1-mini"], Literal["gpt-image-1.5"], str]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) + ) + """Is one of the following types: Literal[\"gpt-image-1\"], Literal[\"gpt-image-1-mini\"], + Literal[\"gpt-image-1.5\"], str""" + quality: Optional[Literal["low", "medium", "high", "auto"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The quality of the generated image. One of ``low``, ``medium``, ``high``, or ``auto``. Default: + ``auto``. Is one of the following types: Literal[\"low\"], Literal[\"medium\"], + Literal[\"high\"], Literal[\"auto\"]""" + size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The size of the generated image. One of ``1024x1024``, ``1024x1536``, ``1536x1024``, or + ``auto``. Default: ``auto``. Is one of the following types: Literal[\"1024x1024\"], + Literal[\"1024x1536\"], Literal[\"1536x1024\"], Literal[\"auto\"]""" + output_format: Optional[Literal["png", "webp", "jpeg"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The output format of the generated image. One of ``png``, ``webp``, or ``jpeg``. Default: + ``png``. Is one of the following types: Literal[\"png\"], Literal[\"webp\"], Literal[\"jpeg\"]""" + output_compression: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Compression level for the output image. Default: 100.""" + moderation: Optional[Literal["auto", "low"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Moderation level for the generated image. Default: ``auto``. Is either a Literal[\"auto\"] type + or a Literal[\"low\"] type.""" + background: Optional[Literal["transparent", "opaque", "auto"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Background type for the generated image. One of ``transparent``, ``opaque``, or ``auto``. + Default: ``auto``. Is one of the following types: Literal[\"transparent\"], + Literal[\"opaque\"], Literal[\"auto\"]""" + input_fidelity: Optional[Union[str, "_models.InputFidelity"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"high\" and \"low\".""" + input_image_mask: Optional["_models.ImageGenToolInputImageMask"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional mask for inpainting. Contains ``image_url`` (string, optional) and ``file_id`` + (string, optional).""" + partial_images: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of partial images to generate in streaming mode, from 0 (default value) to 3.""" + action: Optional[Union[str, "_models.ImageGenAction"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Whether to generate a new image or edit an existing image. Default: ``auto``. Known values are: + \"generate\", \"edit\", and \"auto\".""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + model: Optional[ + Union[Literal["gpt-image-1"], Literal["gpt-image-1-mini"], Literal["gpt-image-1.5"], str] + ] = None, + quality: Optional[Literal["low", "medium", "high", "auto"]] = None, + size: Optional[Literal["1024x1024", "1024x1536", "1536x1024", "auto"]] = None, + output_format: Optional[Literal["png", "webp", "jpeg"]] = None, + output_compression: Optional[int] = None, + moderation: Optional[Literal["auto", "low"]] = None, + background: Optional[Literal["transparent", "opaque", "auto"]] = None, + input_fidelity: Optional[Union[str, "_models.InputFidelity"]] = None, + input_image_mask: Optional["_models.ImageGenToolInputImageMask"] = None, + partial_images: Optional[int] = None, + action: Optional[Union[str, "_models.ImageGenAction"]] = None, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = 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.IMAGE_GENERATION # type: ignore + + +class ImageGenToolInputImageMask(_Model): + """ImageGenToolInputImageMask. + + :ivar image_url: + :vartype image_url: str + :ivar file_id: + :vartype file_id: str + """ + + image_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + file_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + image_url: Optional[str] = None, + file_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 InlineSkillParam(ContainerSkill, discriminator="inline"): + """InlineSkillParam. + + :ivar type: Defines an inline skill for this request. Required. INLINE. + :vartype type: str or ~azure.ai.projects.models.INLINE + :ivar name: The name of the skill. Required. + :vartype name: str + :ivar description: The description of the skill. Required. + :vartype description: str + :ivar source: Inline skill payload. Required. + :vartype source: ~azure.ai.projects.models.InlineSkillSourceParam + """ + + type: Literal[ContainerSkillType.INLINE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Defines an inline skill for this request. Required. INLINE.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the skill. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The description of the skill. Required.""" + source: "_models.InlineSkillSourceParam" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Inline skill payload. Required.""" + + @overload + def __init__( + self, + *, + name: str, + description: str, + source: "_models.InlineSkillSourceParam", + ) -> 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 = ContainerSkillType.INLINE # type: ignore + + +class InlineSkillSourceParam(_Model): + """Inline skill payload. + + :ivar type: The type of the inline skill source. Must be ``base64``. Required. Default value is + "base64". + :vartype type: str + :ivar media_type: The media type of the inline skill payload. Must be ``application/zip``. + Required. Default value is "application/zip". + :vartype media_type: str + :ivar data: Base64-encoded skill zip bundle. Required. + :vartype data: str + """ + + type: Literal["base64"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The type of the inline skill source. Must be ``base64``. Required. Default value is \"base64\".""" + media_type: Literal["application/zip"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The media type of the inline skill payload. Must be ``application/zip``. Required. Default + value is \"application/zip\".""" + data: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64-encoded skill zip bundle. Required.""" + + @overload + def __init__( + self, + *, + data: 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["base64"] = "base64" + self.media_type: Literal["application/zip"] = "application/zip" + + +class Insight(_Model): + """The response body for cluster insights. + + :ivar insight_id: The unique identifier for the insights report. Required. + :vartype insight_id: str + :ivar metadata: Metadata about the insights report. Required. + :vartype metadata: ~azure.ai.projects.models.InsightsMetadata + :ivar state: The current state of the insights. Required. Known values are: "NotStarted", + "Running", "Succeeded", "Failed", and "Canceled". + :vartype state: str or ~azure.ai.projects.models.OperationState + :ivar display_name: User friendly display name for the insight. Required. + :vartype display_name: str + :ivar request: Request for the insights analysis. Required. + :vartype request: ~azure.ai.projects.models.InsightRequest + :ivar result: The result of the insights report. + :vartype result: ~azure.ai.projects.models.InsightResult + """ + + insight_id: str = rest_field(name="id", visibility=["read"]) + """The unique identifier for the insights report. Required.""" + metadata: "_models.InsightsMetadata" = rest_field(visibility=["read"]) + """Metadata about the insights report. Required.""" + state: Union[str, "_models.OperationState"] = rest_field(visibility=["read"]) + """The current state of the insights. Required. Known values are: \"NotStarted\", \"Running\", + \"Succeeded\", \"Failed\", and \"Canceled\".""" + display_name: str = rest_field(name="displayName", visibility=["read", "create", "update", "delete", "query"]) + """User friendly display name for the insight. Required.""" + request: "_models.InsightRequest" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Request for the insights analysis. Required.""" + result: Optional["_models.InsightResult"] = rest_field(visibility=["read"]) + """The result of the insights report.""" + + @overload + def __init__( + self, + *, + display_name: str, + request: "_models.InsightRequest", + ) -> 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 InsightCluster(_Model): + """A cluster of analysis samples. + + :ivar id: The id of the analysis cluster. Required. + :vartype id: str + :ivar label: Label for the cluster. Required. + :vartype label: str + :ivar suggestion: Suggestion for the cluster. Required. + :vartype suggestion: str + :ivar suggestion_title: The title of the suggestion for the cluster. Required. + :vartype suggestion_title: str + :ivar description: Description of the analysis cluster. Required. + :vartype description: str + :ivar weight: The weight of the analysis cluster. This indicate number of samples in the + cluster. Required. + :vartype weight: int + :ivar sub_clusters: List of subclusters within this cluster. Empty if no subclusters exist. + :vartype sub_clusters: list[~azure.ai.projects.models.InsightCluster] + :ivar samples: List of samples that belong to this cluster. Empty if samples are part of + subclusters. + :vartype samples: list[~azure.ai.projects.models.InsightSample] + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The id of the analysis cluster. Required.""" + label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Label for the cluster. Required.""" + suggestion: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Suggestion for the cluster. Required.""" + suggestion_title: str = rest_field( + name="suggestionTitle", visibility=["read", "create", "update", "delete", "query"] + ) + """The title of the suggestion for the cluster. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description of the analysis cluster. Required.""" + weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The weight of the analysis cluster. This indicate number of samples in the cluster. Required.""" + sub_clusters: Optional[list["_models.InsightCluster"]] = rest_field( + name="subClusters", visibility=["read", "create", "update", "delete", "query"] + ) + """List of subclusters within this cluster. Empty if no subclusters exist.""" + samples: Optional[list["_models.InsightSample"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """List of samples that belong to this cluster. Empty if samples are part of subclusters.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + label: str, + suggestion: str, + suggestion_title: str, + description: str, + weight: int, + sub_clusters: Optional[list["_models.InsightCluster"]] = None, + samples: Optional[list["_models.InsightSample"]] = 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 InsightModelConfiguration(_Model): + """Configuration of the model used in the insight generation. + + :ivar model_deployment_name: The model deployment to be evaluated. Accepts either the + deployment name alone or with the connection name as '{connectionName}/'. + Required. + :vartype model_deployment_name: str + """ + + model_deployment_name: str = rest_field( + name="modelDeploymentName", visibility=["read", "create", "update", "delete", "query"] + ) + """The model deployment to be evaluated. Accepts either the deployment name alone or with the + connection name as '{connectionName}/'. Required.""" + + @overload + def __init__( + self, + *, + model_deployment_name: 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 InsightScheduleTask(ScheduleTask, discriminator="Insight"): + """Insight task for the schedule. + + :ivar configuration: Configuration for the task. + :vartype configuration: dict[str, str] + :ivar type: Required. Insight task. + :vartype type: str or ~azure.ai.projects.models.INSIGHT + :ivar insight: The insight payload. Required. + :vartype insight: ~azure.ai.projects.models.Insight + """ + + type: Literal[ScheduleTaskType.INSIGHT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Insight task.""" + insight: "_models.Insight" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The insight payload. Required.""" + + @overload + def __init__( + self, + *, + insight: "_models.Insight", + 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.INSIGHT # type: ignore + + +class InsightsMetadata(_Model): + """Metadata about the insights. + + :ivar created_at: The timestamp when the insights were created. Required. + :vartype created_at: ~datetime.datetime + :ivar completed_at: The timestamp when the insights were completed. + :vartype completed_at: ~datetime.datetime + """ + + created_at: datetime.datetime = rest_field( + name="createdAt", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """The timestamp when the insights were created. Required.""" + completed_at: Optional[datetime.datetime] = rest_field( + name="completedAt", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """The timestamp when the insights were completed.""" + + @overload + def __init__( + self, + *, + created_at: datetime.datetime, + completed_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 InsightSummary(_Model): + """Summary of the error cluster analysis. + + :ivar sample_count: Total number of samples analyzed. Required. + :vartype sample_count: int + :ivar unique_subcluster_count: Total number of unique subcluster labels. Required. + :vartype unique_subcluster_count: int + :ivar unique_cluster_count: Total number of unique clusters. Required. + :vartype unique_cluster_count: int + :ivar method: Method used for clustering. Required. + :vartype method: str + :ivar usage: Token usage while performing clustering analysis. Required. + :vartype usage: ~azure.ai.projects.models.ClusterTokenUsage + """ + + sample_count: int = rest_field(name="sampleCount", visibility=["read", "create", "update", "delete", "query"]) + """Total number of samples analyzed. Required.""" + unique_subcluster_count: int = rest_field( + name="uniqueSubclusterCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Total number of unique subcluster labels. Required.""" + unique_cluster_count: int = rest_field( + name="uniqueClusterCount", visibility=["read", "create", "update", "delete", "query"] + ) + """Total number of unique clusters. Required.""" + method: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Method used for clustering. Required.""" + usage: "_models.ClusterTokenUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Token usage while performing clustering analysis. Required.""" + + @overload + def __init__( + self, + *, + sample_count: int, + unique_subcluster_count: int, + unique_cluster_count: int, + method: str, + usage: "_models.ClusterTokenUsage", + ) -> 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 RoutineDispatchPayload(_Model): + """Base model for a manual dispatch payload. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + InvokeAgentInvocationsApiDispatchPayload, InvokeAgentResponsesApiDispatchPayload + + :ivar type: The manual dispatch payload type. Required. Known values are: + "invoke_agent_responses_api" and "invoke_agent_invocations_api". + :vartype type: str or ~azure.ai.projects.models.RoutineDispatchPayloadType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The manual dispatch payload type. Required. Known values are: \"invoke_agent_responses_api\" + and \"invoke_agent_invocations_api\".""" + + @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 InvokeAgentInvocationsApiDispatchPayload(RoutineDispatchPayload, discriminator="invoke_agent_invocations_api"): + """A manual payload used to test an invocations API routine dispatch. + + :ivar type: The manual dispatch payload type. Required. A manual payload for an invocations API + routine dispatch. + :vartype type: str or ~azure.ai.projects.models.INVOKE_AGENT_INVOCATIONS_API + :ivar input: The raw input sent to the downstream invocations target. + :vartype input: str + """ + + type: Literal[RoutineDispatchPayloadType.INVOKE_AGENT_INVOCATIONS_API] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The manual dispatch payload type. Required. A manual payload for an invocations API routine + dispatch.""" + input: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The raw input sent to the downstream invocations target.""" + + @overload + def __init__( + self, + *, + input: 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 = RoutineDispatchPayloadType.INVOKE_AGENT_INVOCATIONS_API # type: ignore + + +class RoutineAction(_Model): + """Base model for a routine action. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + InvokeAgentInvocationsApiRoutineAction, InvokeAgentResponsesApiRoutineAction + + :ivar type: The action type. Required. Known values are: "invoke_agent_responses_api" and + "invoke_agent_invocations_api". + :vartype type: str or ~azure.ai.projects.models.RoutineActionType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The action type. Required. Known values are: \"invoke_agent_responses_api\" and + \"invoke_agent_invocations_api\".""" + + @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 InvokeAgentInvocationsApiRoutineAction(RoutineAction, discriminator="invoke_agent_invocations_api"): + """Dispatches a routine through the raw invocations API. + + :ivar type: The action type. Required. Dispatches through the raw invocations API. + :vartype type: str or ~azure.ai.projects.models.INVOKE_AGENT_INVOCATIONS_API + :ivar agent_endpoint_id: The endpoint-scoped agent identifier for invocations API dispatch. + Required. + :vartype agent_endpoint_id: str + :ivar session_id: An optional existing hosted-agent session identifier to continue during the + downstream dispatch. + :vartype session_id: str + """ + + type: Literal[RoutineActionType.INVOKE_AGENT_INVOCATIONS_API] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The action type. Required. Dispatches through the raw invocations API.""" + agent_endpoint_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The endpoint-scoped agent identifier for invocations API dispatch. Required.""" + session_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional existing hosted-agent session identifier to continue during the downstream + dispatch.""" + + @overload + def __init__( + self, + *, + agent_endpoint_id: str, + session_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) + self.type = RoutineActionType.INVOKE_AGENT_INVOCATIONS_API # type: ignore + + +class InvokeAgentResponsesApiDispatchPayload(RoutineDispatchPayload, discriminator="invoke_agent_responses_api"): + """A manual payload used to test a responses API routine dispatch. + + :ivar type: The manual dispatch payload type. Required. A manual payload for a responses API + routine dispatch. + :vartype type: str or ~azure.ai.projects.models.INVOKE_AGENT_RESPONSES_API + :ivar input: The user input sent to the downstream responses target. + :vartype input: str + """ + + type: Literal[RoutineDispatchPayloadType.INVOKE_AGENT_RESPONSES_API] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The manual dispatch payload type. Required. A manual payload for a responses API routine + dispatch.""" + input: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The user input sent to the downstream responses target.""" + + @overload + def __init__( + self, + *, + input: 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 = RoutineDispatchPayloadType.INVOKE_AGENT_RESPONSES_API # type: ignore + + +class InvokeAgentResponsesApiRoutineAction(RoutineAction, discriminator="invoke_agent_responses_api"): + """Dispatches a routine through the responses API. Exactly one of agent_name or agent_endpoint_id + must be provided. + + :ivar type: The action type. Required. Dispatches through the responses API. + :vartype type: str or ~azure.ai.projects.models.INVOKE_AGENT_RESPONSES_API + :ivar agent_name: The project-scoped agent name for responses API dispatch. + :vartype agent_name: str + :ivar agent_endpoint_id: The endpoint-scoped agent identifier for responses API dispatch. + :vartype agent_endpoint_id: str + :ivar conversation_id: An optional existing conversation identifier to continue during the + downstream dispatch. + :vartype conversation_id: str + """ + + type: Literal[RoutineActionType.INVOKE_AGENT_RESPONSES_API] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The action type. Required. Dispatches through the responses API.""" + agent_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The project-scoped agent name for responses API dispatch.""" + agent_endpoint_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The endpoint-scoped agent identifier for responses API dispatch.""" + conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional existing conversation identifier to continue during the downstream dispatch.""" + + @overload + def __init__( + self, + *, + agent_name: Optional[str] = None, + agent_endpoint_id: Optional[str] = None, + conversation_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) + self.type = RoutineActionType.INVOKE_AGENT_RESPONSES_API # type: ignore + + +class LocalShellToolParam(Tool, discriminator="local_shell"): + """Local shell tool. + + :ivar type: The type of the local shell tool. Always ``local_shell``. Required. LOCAL_SHELL. + :vartype type: str or ~azure.ai.projects.models.LOCAL_SHELL + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.LOCAL_SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the local shell tool. Always ``local_shell``. Required. LOCAL_SHELL.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = 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.LOCAL_SHELL # type: ignore + + +class LocalSkillParam(_Model): + """LocalSkillParam. + + :ivar name: The name of the skill. Required. + :vartype name: str + :ivar description: The description of the skill. Required. + :vartype description: str + :ivar path: The path to the directory containing the skill. Required. + :vartype path: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the skill. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The description of the skill. Required.""" + path: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The path to the directory containing the skill. Required.""" + + @overload + def __init__( + self, + *, + name: str, + description: str, + path: 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 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. + + :ivar type: Required. MANAGED_AGENT_IDENTITY_BLUEPRINT. + :vartype type: str or ~azure.ai.projects.models.MANAGED_AGENT_IDENTITY_BLUEPRINT + :ivar blueprint_id: The ID of the managed blueprint. Required. + :vartype blueprint_id: str + """ + + type: Literal[AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. MANAGED_AGENT_IDENTITY_BLUEPRINT.""" + blueprint_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the managed blueprint. Required.""" + + @overload + def __init__( + self, + *, + blueprint_id: 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 = AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT # type: ignore + + +class ManagedAzureAISearchIndex(Index, discriminator="ManagedAzureSearch"): + """Managed Azure AI Search Index Definition. + + :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 type: Type of index. Required. Managed Azure Search. + :vartype type: str or ~azure.ai.projects.models.MANAGED_AZURE_SEARCH + :ivar vector_store_id: Vector store id of managed index. Required. + :vartype vector_store_id: str + """ + + type: Literal[IndexType.MANAGED_AZURE_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Type of index. Required. Managed Azure Search.""" + vector_store_id: str = rest_field(name="vectorStoreId", visibility=["create"]) + """Vector store id of managed index. Required.""" + + @overload + def __init__( + self, + *, + vector_store_id: str, + 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) + self.type = IndexType.MANAGED_AZURE_SEARCH # type: ignore + + +class MCPTool(Tool, discriminator="mcp"): + """MCP tool. + + :ivar type: The type of the MCP tool. Always ``mcp``. Required. MCP. + :vartype type: str or ~azure.ai.projects.models.MCP + :ivar server_label: A label for this MCP server, used to identify it in tool calls. Required. + :vartype server_label: str + :ivar server_url: The URL for the MCP server. One of ``server_url`` or ``connector_id`` must be + provided. + :vartype server_url: str + :ivar connector_id: Identifier for service connectors, like those available in ChatGPT. One of + ``server_url`` or ``connector_id`` must be provided. Learn more about service connectors `here + `_. Currently supported ``connector_id`` values are: + + * Dropbox: `connector_dropbox` + * Gmail: `connector_gmail` + * Google Calendar: `connector_googlecalendar` + * Google Drive: `connector_googledrive` + * Microsoft Teams: `connector_microsoftteams` + * Outlook Calendar: `connector_outlookcalendar` + * Outlook Email: `connector_outlookemail` + * SharePoint: `connector_sharepoint`. Is one of the following types: + Literal["connector_dropbox"], Literal["connector_gmail"], Literal["connector_googlecalendar"], + Literal["connector_googledrive"], Literal["connector_microsoftteams"], + Literal["connector_outlookcalendar"], Literal["connector_outlookemail"], + Literal["connector_sharepoint"] + :vartype connector_id: str or str or str or str or str or str or str or str + :ivar authorization: An OAuth access token that can be used with a remote MCP server, either + with a custom MCP server URL or a service connector. Your application must handle the OAuth + authorization flow and provide the token here. + :vartype authorization: str + :ivar server_description: Optional description of the MCP server, used to provide more context. + :vartype server_description: str + :ivar headers: + :vartype headers: dict[str, str] + :ivar allowed_tools: Is either a [str] type or a MCPToolFilter type. + :vartype allowed_tools: list[str] or ~azure.ai.projects.models.MCPToolFilter + :ivar require_approval: Is one of the following types: MCPToolRequireApproval, + Literal["always"], Literal["never"] + :vartype require_approval: ~azure.ai.projects.models.MCPToolRequireApproval or str or str + :ivar project_connection_id: The connection ID in the project for the MCP server. The + connection stores authentication and other connection details needed to connect to the MCP + server. + :vartype project_connection_id: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the MCP tool. Always ``mcp``. Required. MCP.""" + server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A label for this MCP server, used to identify it in tool calls. Required.""" + server_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The URL for the MCP server. One of ``server_url`` or ``connector_id`` must be provided.""" + connector_id: Optional[ + Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for service connectors, like those available in ChatGPT. One of ``server_url`` or + ``connector_id`` must be provided. Learn more about service connectors `here + `_. Currently supported ``connector_id`` values are: + + * Dropbox: `connector_dropbox` + * Gmail: `connector_gmail` + * Google Calendar: `connector_googlecalendar` + * Google Drive: `connector_googledrive` + * Microsoft Teams: `connector_microsoftteams` + * Outlook Calendar: `connector_outlookcalendar` + * Outlook Email: `connector_outlookemail` + * SharePoint: `connector_sharepoint`. Is one of the following types: + Literal[\"connector_dropbox\"], Literal[\"connector_gmail\"], + Literal[\"connector_googlecalendar\"], Literal[\"connector_googledrive\"], + Literal[\"connector_microsoftteams\"], Literal[\"connector_outlookcalendar\"], + Literal[\"connector_outlookemail\"], Literal[\"connector_sharepoint\"]""" + authorization: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An OAuth access token that can be used with a remote MCP server, either with a custom MCP + server URL or a service connector. Your application must handle the OAuth authorization flow + and provide the token here.""" + server_description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional description of the MCP server, used to provide more context.""" + headers: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + allowed_tools: Optional[Union[list[str], "_models.MCPToolFilter"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is either a [str] type or a MCPToolFilter type.""" + require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) + ) + """Is one of the following types: MCPToolRequireApproval, Literal[\"always\"], Literal[\"never\"]""" + project_connection_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The connection ID in the project for the MCP server. The connection stores authentication and + other connection details needed to connect to the MCP server.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + server_label: str, + server_url: Optional[str] = None, + connector_id: Optional[ + Literal[ + "connector_dropbox", + "connector_gmail", + "connector_googlecalendar", + "connector_googledrive", + "connector_microsoftteams", + "connector_outlookcalendar", + "connector_outlookemail", + "connector_sharepoint", + ] + ] = None, + authorization: Optional[str] = None, + server_description: Optional[str] = None, + headers: Optional[dict[str, str]] = None, + allowed_tools: Optional[Union[list[str], "_models.MCPToolFilter"]] = None, + require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = None, + project_connection_id: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -6070,48 +9055,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["base64"] = "base64" - self.media_type: Literal["application/zip"] = "application/zip" + self.type = ToolType.MCP # type: ignore -class Insight(_Model): - """The response body for cluster insights. +class MCPToolFilter(_Model): + """MCP tool filter. - :ivar insight_id: The unique identifier for the insights report. Required. - :vartype insight_id: str - :ivar metadata: Metadata about the insights report. Required. - :vartype metadata: ~azure.ai.projects.models.InsightsMetadata - :ivar state: The current state of the insights. Required. Known values are: "NotStarted", - "Running", "Succeeded", "Failed", and "Canceled". - :vartype state: str or ~azure.ai.projects.models.OperationState - :ivar display_name: User friendly display name for the insight. Required. - :vartype display_name: str - :ivar request: Request for the insights analysis. Required. - :vartype request: ~azure.ai.projects.models.InsightRequest - :ivar result: The result of the insights report. - :vartype result: ~azure.ai.projects.models.InsightResult + :ivar tool_names: MCP allowed tools. + :vartype tool_names: list[str] + :ivar read_only: Indicates whether or not a tool modifies data or is read-only. If an MCP + server is `annotated with `readOnlyHint` + `_, + it will match this filter. + :vartype read_only: bool """ - insight_id: str = rest_field(name="id", visibility=["read"]) - """The unique identifier for the insights report. Required.""" - metadata: "_models.InsightsMetadata" = rest_field(visibility=["read"]) - """Metadata about the insights report. Required.""" - state: Union[str, "_models.OperationState"] = rest_field(visibility=["read"]) - """The current state of the insights. Required. Known values are: \"NotStarted\", \"Running\", - \"Succeeded\", \"Failed\", and \"Canceled\".""" - display_name: str = rest_field(name="displayName", visibility=["read", "create", "update", "delete", "query"]) - """User friendly display name for the insight. Required.""" - request: "_models.InsightRequest" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Request for the insights analysis. Required.""" - result: Optional["_models.InsightResult"] = rest_field(visibility=["read"]) - """The result of the insights report.""" + tool_names: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """MCP allowed tools.""" + read_only: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Indicates whether or not a tool modifies data or is read-only. If an MCP server is `annotated + with `readOnlyHint` + `_, + it will match this filter.""" @overload def __init__( self, *, - display_name: str, - request: "_models.InsightRequest", + tool_names: Optional[list[str]] = None, + read_only: Optional[bool] = None, ) -> None: ... @overload @@ -6125,64 +9097,24 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InsightCluster(_Model): - """A cluster of analysis samples. +class MCPToolRequireApproval(_Model): + """MCPToolRequireApproval. - :ivar id: The id of the analysis cluster. Required. - :vartype id: str - :ivar label: Label for the cluster. Required. - :vartype label: str - :ivar suggestion: Suggestion for the cluster. Required. - :vartype suggestion: str - :ivar suggestion_title: The title of the suggestion for the cluster. Required. - :vartype suggestion_title: str - :ivar description: Description of the analysis cluster. Required. - :vartype description: str - :ivar weight: The weight of the analysis cluster. This indicate number of samples in the - cluster. Required. - :vartype weight: int - :ivar sub_clusters: List of subclusters within this cluster. Empty if no subclusters exist. - :vartype sub_clusters: list[~azure.ai.projects.models.InsightCluster] - :ivar samples: List of samples that belong to this cluster. Empty if samples are part of - subclusters. - :vartype samples: list[~azure.ai.projects.models.InsightSample] + :ivar always: + :vartype always: ~azure.ai.projects.models.MCPToolFilter + :ivar never: + :vartype never: ~azure.ai.projects.models.MCPToolFilter """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The id of the analysis cluster. Required.""" - label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Label for the cluster. Required.""" - suggestion: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Suggestion for the cluster. Required.""" - suggestion_title: str = rest_field( - name="suggestionTitle", visibility=["read", "create", "update", "delete", "query"] - ) - """The title of the suggestion for the cluster. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description of the analysis cluster. Required.""" - weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The weight of the analysis cluster. This indicate number of samples in the cluster. Required.""" - sub_clusters: Optional[list["_models.InsightCluster"]] = rest_field( - name="subClusters", visibility=["read", "create", "update", "delete", "query"] - ) - """List of subclusters within this cluster. Empty if no subclusters exist.""" - samples: Optional[list["_models.InsightSample"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """List of samples that belong to this cluster. Empty if samples are part of subclusters.""" + always: Optional["_models.MCPToolFilter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + never: Optional["_models.MCPToolFilter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - label: str, - suggestion: str, - suggestion_title: str, - description: str, - weight: int, - sub_clusters: Optional[list["_models.InsightCluster"]] = None, - samples: Optional[list["_models.InsightSample"]] = None, + always: Optional["_models.MCPToolFilter"] = None, + never: Optional["_models.MCPToolFilter"] = None, ) -> None: ... @overload @@ -6196,26 +9128,30 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InsightModelConfiguration(_Model): - """Configuration of the model used in the insight generation. +class MemoryOperation(_Model): + """Represents a single memory operation (create, update, or delete) performed on a memory item. - :ivar model_deployment_name: The model deployment to be evaluated. Accepts either the - deployment name alone or with the connection name as '{connectionName}/'. - Required. - :vartype model_deployment_name: str + :ivar kind: The type of memory operation being performed. Required. Known values are: "create", + "update", and "delete". + :vartype kind: str or ~azure.ai.projects.models.MemoryOperationKind + :ivar memory_item: The memory item to create, update, or delete. Required. + :vartype memory_item: ~azure.ai.projects.models.MemoryItem """ - model_deployment_name: str = rest_field( - name="modelDeploymentName", visibility=["read", "create", "update", "delete", "query"] + kind: Union[str, "_models.MemoryOperationKind"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The model deployment to be evaluated. Accepts either the deployment name alone or with the - connection name as '{connectionName}/'. Required.""" + """The type of memory operation being performed. Required. Known values are: \"create\", + \"update\", and \"delete\".""" + memory_item: "_models.MemoryItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The memory item to create, update, or delete. Required.""" @overload def __init__( self, *, - model_deployment_name: str, + kind: Union[str, "_models.MemoryOperationKind"], + memory_item: "_models.MemoryItem", ) -> None: ... @overload @@ -6229,28 +9165,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InsightScheduleTask(ScheduleTask, discriminator="Insight"): - """Insight task for the schedule. +class MemorySearchItem(_Model): + """A retrieved memory item from memory search. - :ivar configuration: Configuration for the task. - :vartype configuration: dict[str, str] - :ivar type: Required. Insight task. - :vartype type: str or ~azure.ai.projects.models.INSIGHT - :ivar insight: The insight payload. Required. - :vartype insight: ~azure.ai.projects.models.Insight + :ivar memory_item: Retrieved memory item. Required. + :vartype memory_item: ~azure.ai.projects.models.MemoryItem """ - type: Literal[ScheduleTaskType.INSIGHT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Insight task.""" - insight: "_models.Insight" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The insight payload. Required.""" + memory_item: "_models.MemoryItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Retrieved memory item. Required.""" @overload def __init__( self, *, - insight: "_models.Insight", - configuration: Optional[dict[str, str]] = None, + memory_item: "_models.MemoryItem", ) -> None: ... @overload @@ -6262,33 +9191,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ScheduleTaskType.INSIGHT # type: ignore -class InsightsMetadata(_Model): - """Metadata about the insights. +class MemorySearchOptions(_Model): + """Memory search options. - :ivar created_at: The timestamp when the insights were created. Required. - :vartype created_at: ~datetime.datetime - :ivar completed_at: The timestamp when the insights were completed. - :vartype completed_at: ~datetime.datetime + :ivar max_memories: Maximum number of memory items to return. + :vartype max_memories: int """ - created_at: datetime.datetime = rest_field( - name="createdAt", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" - ) - """The timestamp when the insights were created. Required.""" - completed_at: Optional[datetime.datetime] = rest_field( - name="completedAt", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" - ) - """The timestamp when the insights were completed.""" + max_memories: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of memory items to return.""" @overload def __init__( self, *, - created_at: datetime.datetime, - completed_at: Optional[datetime.datetime] = None, + max_memories: Optional[int] = None, ) -> None: ... @overload @@ -6302,45 +9221,69 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InsightSummary(_Model): - """Summary of the error cluster analysis. +class MemorySearchPreviewTool(Tool, discriminator="memory_search_preview"): + """A tool for integrating memories into the agent. - :ivar sample_count: Total number of samples analyzed. Required. - :vartype sample_count: int - :ivar unique_subcluster_count: Total number of unique subcluster labels. Required. - :vartype unique_subcluster_count: int - :ivar unique_cluster_count: Total number of unique clusters. Required. - :vartype unique_cluster_count: int - :ivar method: Method used for clustering. Required. - :vartype method: str - :ivar usage: Token usage while performing clustering analysis. Required. - :vartype usage: ~azure.ai.projects.models.ClusterTokenUsage + :ivar type: The type of the tool. Always ``memory_search_preview``. Required. + MEMORY_SEARCH_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.MEMORY_SEARCH_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + :ivar memory_store_name: The name of the memory store to use. Required. + :vartype memory_store_name: str + :ivar scope: The namespace used to group and isolate memories, such as a user ID. Limits which + memories can be retrieved or updated. Use special variable ``{{$userId}}`` to scope memories to + the current signed-in user. Required. + :vartype scope: str + :ivar search_options: Options for searching the memory store. + :vartype search_options: ~azure.ai.projects.models.MemorySearchOptions + :ivar update_delay: Time to wait before updating memories after inactivity (seconds). Default + 300. + :vartype update_delay: int """ - sample_count: int = rest_field(name="sampleCount", visibility=["read", "create", "update", "delete", "query"]) - """Total number of samples analyzed. Required.""" - unique_subcluster_count: int = rest_field( - name="uniqueSubclusterCount", visibility=["read", "create", "update", "delete", "query"] + type: Literal[ToolType.MEMORY_SEARCH_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``memory_search_preview``. Required. MEMORY_SEARCH_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Total number of unique subcluster labels. Required.""" - unique_cluster_count: int = rest_field( - name="uniqueClusterCount", visibility=["read", "create", "update", "delete", "query"] + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + memory_store_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the memory store to use. Required.""" + scope: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The namespace used to group and isolate memories, such as a user ID. Limits which memories can + be retrieved or updated. Use special variable ``{{$userId}}`` to scope memories to the current + signed-in user. Required.""" + search_options: Optional["_models.MemorySearchOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Total number of unique clusters. Required.""" - method: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Method used for clustering. Required.""" - usage: "_models.ClusterTokenUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Token usage while performing clustering analysis. Required.""" + """Options for searching the memory store.""" + update_delay: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Time to wait before updating memories after inactivity (seconds). Default 300.""" @overload def __init__( self, *, - sample_count: int, - unique_subcluster_count: int, - unique_cluster_count: int, - method: str, - usage: "_models.ClusterTokenUsage", + memory_store_name: str, + scope: str, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + search_options: Optional["_models.MemorySearchOptions"] = None, + update_delay: Optional[int] = None, ) -> None: ... @overload @@ -6352,32 +9295,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = ToolType.MEMORY_SEARCH_PREVIEW # type: ignore -class LocalShellToolParam(Tool, discriminator="local_shell"): - """Local shell tool. +class MemoryStoreDefinition(_Model): + """Base definition for memory store configurations. - :ivar type: The type of the local shell tool. Always ``local_shell``. Required. LOCAL_SHELL. - :vartype type: str or ~azure.ai.projects.models.LOCAL_SHELL - :ivar name: Optional user-defined name for this tool or configuration. - :vartype name: str - :ivar description: Optional user-defined description for this tool or configuration. - :vartype description: str + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + MemoryStoreDefaultDefinition + + :ivar kind: The kind of the memory store. Required. "default" + :vartype kind: str or ~azure.ai.projects.models.MemoryStoreKind """ - type: Literal[ToolType.LOCAL_SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the local shell tool. Always ``local_shell``. Required. LOCAL_SHELL.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined name for this tool or configuration.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional user-defined description for this tool or configuration.""" + __mapping__: dict[str, _Model] = {} + kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) + """The kind of the memory store. Required. \"default\"""" @overload def __init__( self, *, - name: Optional[str] = None, - description: Optional[str] = None, + kind: str, ) -> None: ... @overload @@ -6389,34 +9328,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.LOCAL_SHELL # type: ignore -class LocalSkillParam(_Model): - """LocalSkillParam. +class MemoryStoreDefaultDefinition(MemoryStoreDefinition, discriminator="default"): + """Default memory store implementation. - :ivar name: The name of the skill. Required. - :vartype name: str - :ivar description: The description of the skill. Required. - :vartype description: str - :ivar path: The path to the directory containing the skill. Required. - :vartype path: str + :ivar kind: The kind of the memory store. Required. The default memory store implementation. + :vartype kind: str or ~azure.ai.projects.models.DEFAULT + :ivar chat_model: The name or identifier of the chat completion model deployment used for + memory processing. Required. + :vartype chat_model: str + :ivar embedding_model: The name or identifier of the embedding model deployment used for memory + processing. Required. + :vartype embedding_model: str + :ivar options: Default memory store options. + :vartype options: ~azure.ai.projects.models.MemoryStoreDefaultOptions """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the skill. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The description of the skill. Required.""" - path: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The path to the directory containing the skill. Required.""" + kind: Literal[MemoryStoreKind.DEFAULT] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The kind of the memory store. Required. The default memory store implementation.""" + chat_model: str = rest_field(visibility=["read", "create"]) + """The name or identifier of the chat completion model deployment used for memory processing. + Required.""" + embedding_model: str = rest_field(visibility=["read", "create"]) + """The name or identifier of the embedding model deployment used for memory processing. Required.""" + options: Optional["_models.MemoryStoreDefaultOptions"] = rest_field(visibility=["read", "create"]) + """Default memory store options.""" @overload def __init__( self, *, - name: str, - description: str, - path: str, + chat_model: str, + embedding_model: str, + options: Optional["_models.MemoryStoreDefaultOptions"] = None, ) -> None: ... @overload @@ -6428,27 +9373,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.kind = MemoryStoreKind.DEFAULT # type: ignore -class ManagedAgentIdentityBlueprintReference(AgentBlueprintReference, discriminator="ManagedAgentIdentityBlueprint"): - """ManagedAgentIdentityBlueprintReference. +class MemoryStoreDefaultOptions(_Model): + """Default memory store configurations. - :ivar type: Required. MANAGED_AGENT_IDENTITY_BLUEPRINT. - :vartype type: str or ~azure.ai.projects.models.MANAGED_AGENT_IDENTITY_BLUEPRINT - :ivar blueprint_id: The ID of the managed blueprint. Required. - :vartype blueprint_id: str + :ivar user_profile_enabled: Whether to enable user profile extraction and storage. Default is + true. Required. + :vartype user_profile_enabled: bool + :ivar user_profile_details: Specific categories or types of user profile information to extract + and store. + :vartype user_profile_details: str + :ivar chat_summary_enabled: Whether to enable chat summary extraction and storage. Defaults to + ``true``. Required. + :vartype chat_summary_enabled: bool + :ivar procedural_memory_enabled: Whether to enable procedural memory extraction and storage. + Defaults to ``true``. + :vartype procedural_memory_enabled: bool + :ivar default_ttl_seconds: The default time-to-live for memories in seconds. A value of ``0`` + indicates that memories do not expire. Defaults to ``0``. + :vartype default_ttl_seconds: int """ - type: Literal[AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. MANAGED_AGENT_IDENTITY_BLUEPRINT.""" - blueprint_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the managed blueprint. Required.""" + user_profile_enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to enable user profile extraction and storage. Default is true. Required.""" + user_profile_details: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Specific categories or types of user profile information to extract and store.""" + chat_summary_enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to enable chat summary extraction and storage. Defaults to ``true``. Required.""" + procedural_memory_enabled: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to enable procedural memory extraction and storage. Defaults to ``true``.""" + default_ttl_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The default time-to-live for memories in seconds. A value of ``0`` indicates that memories do + not expire. Defaults to ``0``.""" @overload def __init__( self, *, - blueprint_id: str, + user_profile_enabled: bool, + chat_summary_enabled: bool, + user_profile_details: Optional[str] = None, + procedural_memory_enabled: Optional[bool] = None, + default_ttl_seconds: Optional[int] = None, ) -> None: ... @overload @@ -6460,40 +9428,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT # type: ignore -class ManagedAzureAISearchIndex(Index, discriminator="ManagedAzureSearch"): - """Managed Azure AI Search Index Definition. +class MemoryStoreDeleteScopeResult(_Model): + """Response for deleting memories from a scope. - :ivar id: Asset ID, a unique identifier for the asset. - :vartype id: str - :ivar name: The name of the resource. Required. + :ivar object: The object type. Always 'memory_store.scope.deleted'. Required. + MEMORY_STORE_SCOPE_DELETED. + :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE_SCOPE_DELETED + :ivar name: The name of the memory store. 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 type: Type of index. Required. Managed Azure Search. - :vartype type: str or ~azure.ai.projects.models.MANAGED_AZURE_SEARCH - :ivar vector_store_id: Vector store id of managed index. Required. - :vartype vector_store_id: str + :ivar scope: The scope from which memories were deleted. Required. + :vartype scope: str + :ivar deleted: Whether the deletion operation was successful. Required. + :vartype deleted: bool """ - type: Literal[IndexType.MANAGED_AZURE_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Type of index. Required. Managed Azure Search.""" - vector_store_id: str = rest_field(name="vectorStoreId", visibility=["create"]) - """Vector store id of managed index. Required.""" + object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The object type. Always 'memory_store.scope.deleted'. Required. MEMORY_STORE_SCOPE_DELETED.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the memory store. Required.""" + scope: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The scope from which memories were deleted. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the deletion operation was successful. Required.""" @overload def __init__( self, *, - vector_store_id: str, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED], + name: str, + scope: str, + deleted: bool, ) -> None: ... @overload @@ -6505,132 +9474,65 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = IndexType.MANAGED_AZURE_SEARCH # type: ignore - -class MCPTool(Tool, discriminator="mcp"): - """MCP tool. - :ivar type: The type of the MCP tool. Always ``mcp``. Required. MCP. - :vartype type: str or ~azure.ai.projects.models.MCP - :ivar server_label: A label for this MCP server, used to identify it in tool calls. Required. - :vartype server_label: str - :ivar server_url: The URL for the MCP server. One of ``server_url`` or ``connector_id`` must be - provided. - :vartype server_url: str - :ivar connector_id: Identifier for service connectors, like those available in ChatGPT. One of - ``server_url`` or ``connector_id`` must be provided. Learn more about service connectors `here - `_. Currently supported ``connector_id`` values are: +class MemoryStoreDetails(_Model): + """A memory store that can store and retrieve user memories. - * Dropbox: `connector_dropbox` - * Gmail: `connector_gmail` - * Google Calendar: `connector_googlecalendar` - * Google Drive: `connector_googledrive` - * Microsoft Teams: `connector_microsoftteams` - * Outlook Calendar: `connector_outlookcalendar` - * Outlook Email: `connector_outlookemail` - * SharePoint: `connector_sharepoint`. Is one of the following types: - Literal["connector_dropbox"], Literal["connector_gmail"], Literal["connector_googlecalendar"], - Literal["connector_googledrive"], Literal["connector_microsoftteams"], - Literal["connector_outlookcalendar"], Literal["connector_outlookemail"], - Literal["connector_sharepoint"] - :vartype connector_id: str or str or str or str or str or str or str or str - :ivar authorization: An OAuth access token that can be used with a remote MCP server, either - with a custom MCP server URL or a service connector. Your application must handle the OAuth - authorization flow and provide the token here. - :vartype authorization: str - :ivar server_description: Optional description of the MCP server, used to provide more context. - :vartype server_description: str - :ivar headers: - :vartype headers: dict[str, str] - :ivar allowed_tools: Is either a [str] type or a MCPToolFilter type. - :vartype allowed_tools: list[str] or ~azure.ai.projects.models.MCPToolFilter - :ivar require_approval: Is one of the following types: MCPToolRequireApproval, - Literal["always"], Literal["never"] - :vartype require_approval: ~azure.ai.projects.models.MCPToolRequireApproval or str or str - :ivar project_connection_id: The connection ID in the project for the MCP server. The - connection stores authentication and other connection details needed to connect to the MCP - server. - :vartype project_connection_id: str + :ivar object: The object type, which is always 'memory_store'. Required. MEMORY_STORE. + :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE + :ivar id: The unique identifier of the memory store. Required. + :vartype id: str + :ivar created_at: The Unix timestamp (seconds) when the memory store was created. Required. + :vartype created_at: ~datetime.datetime + :ivar updated_at: The Unix timestamp (seconds) when the memory store was last updated. + Required. + :vartype updated_at: ~datetime.datetime + :ivar name: The name of the memory store. Required. + :vartype name: str + :ivar description: A human-readable description of the memory store. + :vartype description: str + :ivar metadata: Arbitrary key-value metadata to associate with the memory store. + :vartype metadata: dict[str, str] + :ivar definition: The definition of the memory store. Required. + :vartype definition: ~azure.ai.projects.models.MemoryStoreDefinition """ - type: Literal[ToolType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the MCP tool. Always ``mcp``. Required. MCP.""" - server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A label for this MCP server, used to identify it in tool calls. Required.""" - server_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The URL for the MCP server. One of ``server_url`` or ``connector_id`` must be provided.""" - connector_id: Optional[ - Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for service connectors, like those available in ChatGPT. One of ``server_url`` or - ``connector_id`` must be provided. Learn more about service connectors `here - `_. Currently supported ``connector_id`` values are: - - * Dropbox: `connector_dropbox` - * Gmail: `connector_gmail` - * Google Calendar: `connector_googlecalendar` - * Google Drive: `connector_googledrive` - * Microsoft Teams: `connector_microsoftteams` - * Outlook Calendar: `connector_outlookcalendar` - * Outlook Email: `connector_outlookemail` - * SharePoint: `connector_sharepoint`. Is one of the following types: - Literal[\"connector_dropbox\"], Literal[\"connector_gmail\"], - Literal[\"connector_googlecalendar\"], Literal[\"connector_googledrive\"], - Literal[\"connector_microsoftteams\"], Literal[\"connector_outlookcalendar\"], - Literal[\"connector_outlookemail\"], Literal[\"connector_sharepoint\"]""" - authorization: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An OAuth access token that can be used with a remote MCP server, either with a custom MCP - server URL or a service connector. Your application must handle the OAuth authorization flow - and provide the token here.""" - server_description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of the MCP server, used to provide more context.""" - headers: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - allowed_tools: Optional[Union[list[str], "_models.MCPToolFilter"]] = rest_field( + object: Literal[MemoryStoreObjectType.MEMORY_STORE] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Is either a [str] type or a MCPToolFilter type.""" - require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = ( - rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, which is always 'memory_store'. Required. MEMORY_STORE.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of the memory store. Required.""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (seconds) when the memory store was created. Required.""" + updated_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" ) - """Is one of the following types: MCPToolRequireApproval, Literal[\"always\"], Literal[\"never\"]""" - project_connection_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The connection ID in the project for the MCP server. The connection stores authentication and - other connection details needed to connect to the MCP server.""" + """The Unix timestamp (seconds) when the memory store was last updated. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the memory store. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the memory store.""" + metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Arbitrary key-value metadata to associate with the memory store.""" + definition: "_models.MemoryStoreDefinition" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The definition of the memory store. Required.""" @overload def __init__( self, *, - server_label: str, - server_url: Optional[str] = None, - connector_id: Optional[ - Literal[ - "connector_dropbox", - "connector_gmail", - "connector_googlecalendar", - "connector_googledrive", - "connector_microsoftteams", - "connector_outlookcalendar", - "connector_outlookemail", - "connector_sharepoint", - ] - ] = None, - authorization: Optional[str] = None, - server_description: Optional[str] = None, - headers: Optional[dict[str, str]] = None, - allowed_tools: Optional[Union[list[str], "_models.MCPToolFilter"]] = None, - require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = None, - project_connection_id: Optional[str] = None, + object: Literal[MemoryStoreObjectType.MEMORY_STORE], + id: str, # pylint: disable=redefined-builtin + created_at: datetime.datetime, + updated_at: datetime.datetime, + name: str, + definition: "_models.MemoryStoreDefinition", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -6642,35 +9544,52 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.MCP # type: ignore -class MCPToolFilter(_Model): - """MCP tool filter. +class MemoryStoreOperationUsage(_Model): + """Usage statistics of a memory store operation. - :ivar tool_names: MCP allowed tools. - :vartype tool_names: list[str] - :ivar read_only: Indicates whether or not a tool modifies data or is read-only. If an MCP - server is `annotated with `readOnlyHint` - `_, - it will match this filter. - :vartype read_only: bool + :ivar embedding_tokens: The number of embedding tokens. Required. + :vartype embedding_tokens: int + :ivar input_tokens: The number of input tokens. Required. + :vartype input_tokens: int + :ivar input_tokens_details: A detailed breakdown of the input tokens. Required. + :vartype input_tokens_details: ~azure.ai.projects.models.ResponseUsageInputTokensDetails + :ivar output_tokens: The number of output tokens. Required. + :vartype output_tokens: int + :ivar output_tokens_details: A detailed breakdown of the output tokens. Required. + :vartype output_tokens_details: ~azure.ai.projects.models.ResponseUsageOutputTokensDetails + :ivar total_tokens: The total number of tokens used. Required. + :vartype total_tokens: int """ - tool_names: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """MCP allowed tools.""" - read_only: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Indicates whether or not a tool modifies data or is read-only. If an MCP server is `annotated - with `readOnlyHint` - `_, - it will match this filter.""" + embedding_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of embedding tokens. Required.""" + input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of input tokens. Required.""" + input_tokens_details: "_models.ResponseUsageInputTokensDetails" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """A detailed breakdown of the input tokens. Required.""" + output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of output tokens. Required.""" + output_tokens_details: "_models.ResponseUsageOutputTokensDetails" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """A detailed breakdown of the output tokens. Required.""" + total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The total number of tokens used. Required.""" @overload def __init__( self, *, - tool_names: Optional[list[str]] = None, - read_only: Optional[bool] = None, + embedding_tokens: int, + input_tokens: int, + input_tokens_details: "_models.ResponseUsageInputTokensDetails", + output_tokens: int, + output_tokens_details: "_models.ResponseUsageOutputTokensDetails", + total_tokens: int, ) -> None: ... @overload @@ -6684,24 +9603,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MCPToolRequireApproval(_Model): - """MCPToolRequireApproval. +class MemoryStoreSearchResult(_Model): + """Memory search response. - :ivar always: - :vartype always: ~azure.ai.projects.models.MCPToolFilter - :ivar never: - :vartype never: ~azure.ai.projects.models.MCPToolFilter + :ivar search_id: The unique ID of this search request. Use this value as previous_search_id in + subsequent requests to perform incremental searches. Required. + :vartype search_id: str + :ivar memories: Related memory items found during the search operation. Required. + :vartype memories: list[~azure.ai.projects.models.MemorySearchItem] + :ivar usage: Usage statistics associated with the memory search operation. Required. + :vartype usage: ~azure.ai.projects.models.MemoryStoreOperationUsage """ - always: Optional["_models.MCPToolFilter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - never: Optional["_models.MCPToolFilter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + search_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of this search request. Use this value as previous_search_id in subsequent + requests to perform incremental searches. Required.""" + memories: list["_models.MemorySearchItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Related memory items found during the search operation. Required.""" + usage: "_models.MemoryStoreOperationUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Usage statistics associated with the memory search operation. Required.""" @overload def __init__( self, *, - always: Optional["_models.MCPToolFilter"] = None, - never: Optional["_models.MCPToolFilter"] = None, + search_id: str, + memories: list["_models.MemorySearchItem"], + usage: "_models.MemoryStoreOperationUsage", ) -> None: ... @overload @@ -6715,30 +9643,29 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryOperation(_Model): - """Represents a single memory operation (create, update, or delete) performed on a memory item. +class MemoryStoreUpdateCompletedResult(_Model): + """Memory update result. - :ivar kind: The type of memory operation being performed. Required. Known values are: "create", - "update", and "delete". - :vartype kind: str or ~azure.ai.projects.models.MemoryOperationKind - :ivar memory_item: The memory item to create, update, or delete. Required. - :vartype memory_item: ~azure.ai.projects.models.MemoryItem + :ivar memory_operations: A list of individual memory operations that were performed during the + update. Required. + :vartype memory_operations: list[~azure.ai.projects.models.MemoryOperation] + :ivar usage: Usage statistics associated with the memory update operation. Required. + :vartype usage: ~azure.ai.projects.models.MemoryStoreOperationUsage """ - kind: Union[str, "_models.MemoryOperationKind"] = rest_field( + memory_operations: list["_models.MemoryOperation"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The type of memory operation being performed. Required. Known values are: \"create\", - \"update\", and \"delete\".""" - memory_item: "_models.MemoryItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The memory item to create, update, or delete. Required.""" + """A list of individual memory operations that were performed during the update. Required.""" + usage: "_models.MemoryStoreOperationUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Usage statistics associated with the memory update operation. Required.""" @overload def __init__( self, *, - kind: Union[str, "_models.MemoryOperationKind"], - memory_item: "_models.MemoryItem", + memory_operations: list["_models.MemoryOperation"], + usage: "_models.MemoryStoreOperationUsage", ) -> None: ... @overload @@ -6752,21 +9679,51 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemorySearchItem(_Model): - """A retrieved memory item from memory search. +class MemoryStoreUpdateResult(_Model): + """Provides the status of a memory store update operation. - :ivar memory_item: Retrieved memory item. Required. - :vartype memory_item: ~azure.ai.projects.models.MemoryItem + :ivar update_id: The unique ID of this update request. Use this value as previous_update_id in + subsequent requests to perform incremental updates. Required. + :vartype update_id: str + :ivar status: The status of the memory update operation. One of "queued", "in_progress", + "completed", "failed", or "superseded". Required. Known values are: "queued", "in_progress", + "completed", "failed", and "superseded". + :vartype status: str or ~azure.ai.projects.models.MemoryStoreUpdateStatus + :ivar superseded_by: The update_id the operation was superseded by when status is "superseded". + :vartype superseded_by: str + :ivar result: The result of memory store update operation when status is "completed". + :vartype result: ~azure.ai.projects.models.MemoryStoreUpdateCompletedResult + :ivar error: Error object that describes the error when status is "failed". + :vartype error: ~azure.ai.projects.models.ApiError """ - memory_item: "_models.MemoryItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Retrieved memory item. Required.""" + update_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of this update request. Use this value as previous_update_id in subsequent + requests to perform incremental updates. Required.""" + status: Union[str, "_models.MemoryStoreUpdateStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The status of the memory update operation. One of \"queued\", \"in_progress\", \"completed\", + \"failed\", or \"superseded\". Required. Known values are: \"queued\", \"in_progress\", + \"completed\", \"failed\", and \"superseded\".""" + superseded_by: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The update_id the operation was superseded by when status is \"superseded\".""" + result: Optional["_models.MemoryStoreUpdateCompletedResult"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The result of memory store update operation when status is \"completed\".""" + error: Optional["_models.ApiError"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Error object that describes the error when status is \"failed\".""" @overload def __init__( self, *, - memory_item: "_models.MemoryItem", + update_id: str, + status: Union[str, "_models.MemoryStoreUpdateStatus"], + superseded_by: Optional[str] = None, + result: Optional["_models.MemoryStoreUpdateCompletedResult"] = None, + error: Optional["_models.ApiError"] = None, ) -> None: ... @overload @@ -6780,21 +9737,50 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemorySearchOptions(_Model): - """Memory search options. +class MicrosoftFabricPreviewTool(Tool, discriminator="fabric_dataagent_preview"): + """The input definition information for a Microsoft Fabric tool as used to configure an agent. - :ivar max_memories: Maximum number of memory items to return. - :vartype max_memories: int + :ivar type: The object type, which is always 'fabric_dataagent_preview'. Required. + FABRIC_DATAAGENT_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.FABRIC_DATAAGENT_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + :ivar fabric_dataagent_preview: The fabric data agent tool parameters. Required. + :vartype fabric_dataagent_preview: ~azure.ai.projects.models.FabricDataAgentToolParameters """ - max_memories: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of memory items to return.""" + type: Literal[ToolType.FABRIC_DATAAGENT_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The object type, which is always 'fabric_dataagent_preview'. Required. + FABRIC_DATAAGENT_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + fabric_dataagent_preview: "_models.FabricDataAgentToolParameters" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The fabric data agent tool parameters. Required.""" @overload def __init__( self, *, - max_memories: Optional[int] = None, + fabric_dataagent_preview: "_models.FabricDataAgentToolParameters", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -6806,50 +9792,24 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = ToolType.FABRIC_DATAAGENT_PREVIEW # type: ignore -class MemorySearchPreviewTool(Tool, discriminator="memory_search_preview"): - """A tool for integrating memories into the agent. +class ModelCredentialRequest(_Model): + """Request to fetch credentials for a model asset. - :ivar type: The type of the tool. Always ``memory_search_preview``. Required. - MEMORY_SEARCH_PREVIEW. - :vartype type: str or ~azure.ai.projects.models.MEMORY_SEARCH_PREVIEW - :ivar memory_store_name: The name of the memory store to use. Required. - :vartype memory_store_name: str - :ivar scope: The namespace used to group and isolate memories, such as a user ID. Limits which - memories can be retrieved or updated. Use special variable ``{{$userId}}`` to scope memories to - the current signed-in user. Required. - :vartype scope: str - :ivar search_options: Options for searching the memory store. - :vartype search_options: ~azure.ai.projects.models.MemorySearchOptions - :ivar update_delay: Time to wait before updating memories after inactivity (seconds). Default - 300. - :vartype update_delay: int + :ivar blob_uri: Blob URI of the model asset to fetch credentials for. Required. + :vartype blob_uri: str """ - type: Literal[ToolType.MEMORY_SEARCH_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``memory_search_preview``. Required. MEMORY_SEARCH_PREVIEW.""" - memory_store_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the memory store to use. Required.""" - scope: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The namespace used to group and isolate memories, such as a user ID. Limits which memories can - be retrieved or updated. Use special variable ``{{$userId}}`` to scope memories to the current - signed-in user. Required.""" - search_options: Optional["_models.MemorySearchOptions"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Options for searching the memory store.""" - update_delay: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Time to wait before updating memories after inactivity (seconds). Default 300.""" + 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, *, - memory_store_name: str, - scope: str, - search_options: Optional["_models.MemorySearchOptions"] = None, - update_delay: Optional[int] = None, + blob_uri: str, ) -> None: ... @overload @@ -6861,28 +9821,47 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.MEMORY_SEARCH_PREVIEW # type: ignore - -class MemoryStoreDefinition(_Model): - """Base definition for memory store configurations. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - MemoryStoreDefaultDefinition +class ModelDeployment(Deployment, discriminator="ModelDeployment"): + """Model Deployment Definition. - :ivar kind: The kind of the memory store. Required. "default" - :vartype kind: str or ~azure.ai.projects.models.MemoryStoreKind + :ivar name: Name of the deployment. Required. + :vartype name: str + :ivar type: The type of the deployment. Required. Model deployment. + :vartype type: str or ~azure.ai.projects.models.MODEL_DEPLOYMENT + :ivar model_name: Publisher-specific name of the deployed model. Required. + :vartype model_name: str + :ivar model_version: Publisher-specific version of the deployed model. Required. + :vartype model_version: str + :ivar model_publisher: Name of the deployed model's publisher. Required. + :vartype model_publisher: str + :ivar capabilities: Capabilities of deployed model. Required. + :vartype capabilities: dict[str, str] + :ivar sku: Sku of the model deployment. Required. + :vartype sku: ~azure.ai.projects.models.ModelDeploymentSku + :ivar connection_name: Name of the connection the deployment comes from. + :vartype connection_name: str """ - __mapping__: dict[str, _Model] = {} - kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) - """The kind of the memory store. Required. \"default\"""" + type: Literal[DeploymentType.MODEL_DEPLOYMENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the deployment. Required. Model deployment.""" + model_name: str = rest_field(name="modelName", visibility=["read"]) + """Publisher-specific name of the deployed model. Required.""" + model_version: str = rest_field(name="modelVersion", visibility=["read"]) + """Publisher-specific version of the deployed model. Required.""" + model_publisher: str = rest_field(name="modelPublisher", visibility=["read"]) + """Name of the deployed model's publisher. Required.""" + capabilities: dict[str, str] = rest_field(visibility=["read"]) + """Capabilities of deployed model. Required.""" + sku: "_models.ModelDeploymentSku" = rest_field(visibility=["read"]) + """Sku of the model deployment. Required.""" + connection_name: Optional[str] = rest_field(name="connectionName", visibility=["read"]) + """Name of the connection the deployment comes from.""" @overload def __init__( self, - *, - kind: str, ) -> None: ... @overload @@ -6894,40 +9873,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = DeploymentType.MODEL_DEPLOYMENT # type: ignore -class MemoryStoreDefaultDefinition(MemoryStoreDefinition, discriminator="default"): - """Default memory store implementation. +class ModelDeploymentSku(_Model): + """Sku information. - :ivar kind: The kind of the memory store. Required. The default memory store implementation. - :vartype kind: str or ~azure.ai.projects.models.DEFAULT - :ivar chat_model: The name or identifier of the chat completion model deployment used for - memory processing. Required. - :vartype chat_model: str - :ivar embedding_model: The name or identifier of the embedding model deployment used for memory - processing. Required. - :vartype embedding_model: str - :ivar options: Default memory store options. - :vartype options: ~azure.ai.projects.models.MemoryStoreDefaultOptions + :ivar capacity: Sku capacity. Required. + :vartype capacity: int + :ivar family: Sku family. Required. + :vartype family: str + :ivar name: Sku name. Required. + :vartype name: str + :ivar size: Sku size. Required. + :vartype size: str + :ivar tier: Sku tier. Required. + :vartype tier: str """ - kind: Literal[MemoryStoreKind.DEFAULT] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The kind of the memory store. Required. The default memory store implementation.""" - chat_model: str = rest_field(visibility=["read", "create"]) - """The name or identifier of the chat completion model deployment used for memory processing. - Required.""" - embedding_model: str = rest_field(visibility=["read", "create"]) - """The name or identifier of the embedding model deployment used for memory processing. Required.""" - options: Optional["_models.MemoryStoreDefaultOptions"] = rest_field(visibility=["read", "create"]) - """Default memory store options.""" + capacity: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Sku capacity. Required.""" + family: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Sku family. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Sku name. Required.""" + size: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Sku size. Required.""" + tier: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Sku tier. Required.""" @overload def __init__( self, *, - chat_model: str, - embedding_model: str, - options: Optional["_models.MemoryStoreDefaultOptions"] = None, + capacity: int, + family: str, + name: str, + size: str, + tier: str, ) -> None: ... @overload @@ -6939,37 +9922,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = MemoryStoreKind.DEFAULT # type: ignore -class MemoryStoreDefaultOptions(_Model): - """Default memory store configurations. +class ModelPendingUploadRequest(_Model): + """Represents a request for a pending upload of a model version. - :ivar user_profile_enabled: Whether to enable user profile extraction and storage. Default is - true. Required. - :vartype user_profile_enabled: bool - :ivar user_profile_details: Specific categories or types of user profile information to extract - and store. - :vartype user_profile_details: str - :ivar chat_summary_enabled: Whether to enable chat summary extraction and storage. Default is - true. Required. - :vartype chat_summary_enabled: bool + :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 """ - user_profile_enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether to enable user profile extraction and storage. Default is true. Required.""" - user_profile_details: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Specific categories or types of user profile information to extract and store.""" - chat_summary_enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether to enable chat summary extraction and storage. Default is true. Required.""" + 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, *, - user_profile_enabled: bool, - chat_summary_enabled: bool, - user_profile_details: Optional[str] = None, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + pending_upload_id: Optional[str] = None, + connection_name: Optional[str] = None, ) -> None: ... @overload @@ -6983,39 +9971,45 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreDeleteScopeResult(_Model): - """Response for deleting memories from a scope. +class ModelPendingUploadResponse(_Model): + """Represents the response for a model pending upload request. - :ivar object: The object type. Always 'memory_store.scope.deleted'. Required. - MEMORY_STORE_SCOPE_DELETED. - :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE_SCOPE_DELETED - :ivar name: The name of the memory store. Required. - :vartype name: str - :ivar scope: The scope from which memories were deleted. Required. - :vartype scope: str - :ivar deleted: Whether the deletion operation was successful. Required. - :vartype deleted: bool + :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 """ - object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + blob_reference: "_models.BlobReference" = rest_field( + name="blobReference", visibility=["read", "create", "update", "delete", "query"] ) - """The object type. Always 'memory_store.scope.deleted'. Required. MEMORY_STORE_SCOPE_DELETED.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the memory store. Required.""" - scope: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The scope from which memories were deleted. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the deletion operation was successful. Required.""" + """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, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED], - name: str, - scope: str, - deleted: bool, + blob_reference: "_models.BlobReference", + pending_upload_id: str, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + version: Optional[str] = None, ) -> None: ... @overload @@ -7029,63 +10023,73 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreDetails(_Model): - """A memory store that can store and retrieve user memories. +class ModelSamplingParams(_Model): + """Represents a set of parameters used to control the sampling behavior of a language model during + text generation. - :ivar object: The object type, which is always 'memory_store'. Required. MEMORY_STORE. - :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE - :ivar id: The unique identifier of the memory store. Required. - :vartype id: str - :ivar created_at: The Unix timestamp (seconds) when the memory store was created. Required. - :vartype created_at: ~datetime.datetime - :ivar updated_at: The Unix timestamp (seconds) when the memory store was last updated. - Required. - :vartype updated_at: ~datetime.datetime - :ivar name: The name of the memory store. Required. - :vartype name: str - :ivar description: A human-readable description of the memory store. - :vartype description: str - :ivar metadata: Arbitrary key-value metadata to associate with the memory store. - :vartype metadata: dict[str, str] - :ivar definition: The definition of the memory store. Required. - :vartype definition: ~azure.ai.projects.models.MemoryStoreDefinition + :ivar temperature: The temperature parameter for sampling. Defaults to 1.0. + :vartype temperature: float + :ivar top_p: The top-p parameter for nucleus sampling. Defaults to 1.0. + :vartype top_p: float + :ivar seed: The random seed for reproducibility. Defaults to 42. + :vartype seed: int + :ivar max_completion_tokens: The maximum number of tokens allowed in the completion. + :vartype max_completion_tokens: int """ - object: Literal[MemoryStoreObjectType.MEMORY_STORE] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The object type, which is always 'memory_store'. Required. MEMORY_STORE.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique identifier of the memory store. Required.""" - created_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (seconds) when the memory store was created. Required.""" - updated_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + temperature: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The temperature parameter for sampling. Defaults to 1.0.""" + top_p: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The top-p parameter for nucleus sampling. Defaults to 1.0.""" + seed: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The random seed for reproducibility. Defaults to 42.""" + max_completion_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The maximum number of tokens allowed in the completion.""" + + @overload + def __init__( + self, + *, + temperature: Optional[float] = None, + top_p: Optional[float] = None, + seed: Optional[int] = None, + max_completion_tokens: 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) + + +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 Unix timestamp (seconds) when the memory store was last updated. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the memory store. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A human-readable description of the memory store.""" - metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Arbitrary key-value metadata to associate with the memory store.""" - definition: "_models.MemoryStoreDefinition" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The definition of the memory store. Required.""" + """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, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE], - id: str, # pylint: disable=redefined-builtin - created_at: datetime.datetime, - updated_at: datetime.datetime, - name: str, - definition: "_models.MemoryStoreDefinition", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, + source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = None, + job_id: Optional[str] = None, ) -> None: ... @overload @@ -7099,50 +10103,82 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreOperationUsage(_Model): - """Usage statistics of a memory store operation. +class ModelVersion(_Model): + """Model Version Definition. - :ivar embedding_tokens: The number of embedding tokens. Required. - :vartype embedding_tokens: int - :ivar input_tokens: The number of input tokens. Required. - :vartype input_tokens: int - :ivar input_tokens_details: A detailed breakdown of the input tokens. Required. - :vartype input_tokens_details: ~azure.ai.projects.models.ResponseUsageInputTokensDetails - :ivar output_tokens: The number of output tokens. Required. - :vartype output_tokens: int - :ivar output_tokens_details: A detailed breakdown of the output tokens. Required. - :vartype output_tokens_details: ~azure.ai.projects.models.ResponseUsageOutputTokensDetails - :ivar total_tokens: The total number of tokens used. Required. - :vartype total_tokens: int + :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] """ - embedding_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The number of embedding tokens. Required.""" - input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The number of input tokens. Required.""" - input_tokens_details: "_models.ResponseUsageInputTokensDetails" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """A detailed breakdown of the input tokens. Required.""" - output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The number of output tokens. Required.""" - output_tokens_details: "_models.ResponseUsageOutputTokensDetails" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """A detailed breakdown of the output tokens. Required.""" - total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The total number of tokens used. Required.""" + 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, *, - embedding_tokens: int, - input_tokens: int, - input_tokens_details: "_models.ResponseUsageInputTokensDetails", - output_tokens: int, - output_tokens_details: "_models.ResponseUsageOutputTokensDetails", - total_tokens: int, + 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 @@ -7156,33 +10192,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreSearchResult(_Model): - """Memory search response. +class MonthlyRecurrenceSchedule(RecurrenceSchedule, discriminator="Monthly"): + """Monthly recurrence schedule. - :ivar search_id: The unique ID of this search request. Use this value as previous_search_id in - subsequent requests to perform incremental searches. Required. - :vartype search_id: str - :ivar memories: Related memory items found during the search operation. Required. - :vartype memories: list[~azure.ai.projects.models.MemorySearchItem] - :ivar usage: Usage statistics associated with the memory search operation. Required. - :vartype usage: ~azure.ai.projects.models.MemoryStoreOperationUsage + :ivar type: Monthly recurrence type. Required. Monthly recurrence pattern. + :vartype type: str or ~azure.ai.projects.models.MONTHLY + :ivar days_of_month: Days of the month for the recurrence schedule. Required. + :vartype days_of_month: list[int] """ - search_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of this search request. Use this value as previous_search_id in subsequent - requests to perform incremental searches. Required.""" - memories: list["_models.MemorySearchItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Related memory items found during the search operation. Required.""" - usage: "_models.MemoryStoreOperationUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Usage statistics associated with the memory search operation. Required.""" + type: Literal[RecurrenceType.MONTHLY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Monthly recurrence type. Required. Monthly recurrence pattern.""" + days_of_month: list[int] = rest_field( + name="daysOfMonth", visibility=["read", "create", "update", "delete", "query"] + ) + """Days of the month for the recurrence schedule. Required.""" @overload def __init__( self, *, - search_id: str, - memories: list["_models.MemorySearchItem"], - usage: "_models.MemoryStoreOperationUsage", + days_of_month: list[int], ) -> None: ... @overload @@ -7194,31 +10224,22 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RecurrenceType.MONTHLY # type: ignore -class MemoryStoreUpdateCompletedResult(_Model): - """Memory update result. +class NoAuthenticationCredentials(BaseCredentials, discriminator="None"): + """Credentials that do not require authentication. - :ivar memory_operations: A list of individual memory operations that were performed during the - update. Required. - :vartype memory_operations: list[~azure.ai.projects.models.MemoryOperation] - :ivar usage: Usage statistics associated with the memory update operation. Required. - :vartype usage: ~azure.ai.projects.models.MemoryStoreOperationUsage + :ivar type: The credential type. Required. No credential. + :vartype type: str or ~azure.ai.projects.models.NONE """ - memory_operations: list["_models.MemoryOperation"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """A list of individual memory operations that were performed during the update. Required.""" - usage: "_models.MemoryStoreOperationUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Usage statistics associated with the memory update operation. Required.""" + type: Literal[CredentialType.NONE] = rest_discriminator(name="type", visibility=["read"]) # type: ignore + """The credential type. Required. No credential.""" @overload def __init__( self, - *, - memory_operations: list["_models.MemoryOperation"], - usage: "_models.MemoryStoreOperationUsage", ) -> None: ... @overload @@ -7230,53 +10251,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = CredentialType.NONE # type: ignore -class MemoryStoreUpdateResult(_Model): - """Provides the status of a memory store update operation. +class OneTimeTrigger(Trigger, discriminator="OneTime"): + """One-time trigger. - :ivar update_id: The unique ID of this update request. Use this value as previous_update_id in - subsequent requests to perform incremental updates. Required. - :vartype update_id: str - :ivar status: The status of the memory update operation. One of "queued", "in_progress", - "completed", "failed", or "superseded". Required. Known values are: "queued", "in_progress", - "completed", "failed", and "superseded". - :vartype status: str or ~azure.ai.projects.models.MemoryStoreUpdateStatus - :ivar superseded_by: The update_id the operation was superseded by when status is "superseded". - :vartype superseded_by: str - :ivar result: The result of memory store update operation when status is "completed". - :vartype result: ~azure.ai.projects.models.MemoryStoreUpdateCompletedResult - :ivar error: Error object that describes the error when status is "failed". - :vartype error: ~azure.ai.projects.models.ApiError + :ivar type: Required. One-time trigger. + :vartype type: str or ~azure.ai.projects.models.ONE_TIME + :ivar trigger_at: Date and time for the one-time trigger in ISO 8601 format. Required. + :vartype trigger_at: ~datetime.datetime + :ivar time_zone: Time zone for the one-time trigger. Defaults to ``UTC``. + :vartype time_zone: str """ - update_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of this update request. Use this value as previous_update_id in subsequent - requests to perform incremental updates. Required.""" - status: Union[str, "_models.MemoryStoreUpdateStatus"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The status of the memory update operation. One of \"queued\", \"in_progress\", \"completed\", - \"failed\", or \"superseded\". Required. Known values are: \"queued\", \"in_progress\", - \"completed\", \"failed\", and \"superseded\".""" - superseded_by: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The update_id the operation was superseded by when status is \"superseded\".""" - result: Optional["_models.MemoryStoreUpdateCompletedResult"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + type: Literal[TriggerType.ONE_TIME] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. One-time trigger.""" + trigger_at: datetime.datetime = rest_field( + name="triggerAt", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" ) - """The result of memory store update operation when status is \"completed\".""" - error: Optional["_models.ApiError"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Error object that describes the error when status is \"failed\".""" + """Date and time for the one-time trigger in ISO 8601 format. Required.""" + time_zone: Optional[str] = rest_field(name="timeZone", visibility=["read", "create", "update", "delete", "query"]) + """Time zone for the one-time trigger. Defaults to ``UTC``.""" @overload def __init__( self, *, - update_id: str, - status: Union[str, "_models.MemoryStoreUpdateStatus"], - superseded_by: Optional[str] = None, - result: Optional["_models.MemoryStoreUpdateCompletedResult"] = None, - error: Optional["_models.ApiError"] = None, + trigger_at: datetime.datetime, + time_zone: Optional[str] = None, ) -> None: ... @overload @@ -7288,31 +10291,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = TriggerType.ONE_TIME # type: ignore -class MicrosoftFabricPreviewTool(Tool, discriminator="fabric_dataagent_preview"): - """The input definition information for a Microsoft Fabric tool as used to configure an agent. +class OpenApiAuthDetails(_Model): + """authentication details for OpenApiFunctionDefinition. - :ivar type: The object type, which is always 'fabric_dataagent_preview'. Required. - FABRIC_DATAAGENT_PREVIEW. - :vartype type: str or ~azure.ai.projects.models.FABRIC_DATAAGENT_PREVIEW - :ivar fabric_dataagent_preview: The fabric data agent tool parameters. Required. - :vartype fabric_dataagent_preview: ~azure.ai.projects.models.FabricDataAgentToolParameters + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + OpenApiAnonymousAuthDetails, OpenApiManagedAuthDetails, OpenApiProjectConnectionAuthDetails + + :ivar type: The type of authentication, must be anonymous/project_connection/managed_identity. + Required. Known values are: "anonymous", "project_connection", and "managed_identity". + :vartype type: str or ~azure.ai.projects.models.OpenApiAuthType """ - type: Literal[ToolType.FABRIC_DATAAGENT_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The object type, which is always 'fabric_dataagent_preview'. Required. - FABRIC_DATAAGENT_PREVIEW.""" - fabric_dataagent_preview: "_models.FabricDataAgentToolParameters" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The fabric data agent tool parameters. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of authentication, must be anonymous/project_connection/managed_identity. Required. + Known values are: \"anonymous\", \"project_connection\", and \"managed_identity\".""" @overload def __init__( self, *, - fabric_dataagent_preview: "_models.FabricDataAgentToolParameters", + type: str, ) -> None: ... @overload @@ -7324,44 +10326,17 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.FABRIC_DATAAGENT_PREVIEW # type: ignore -class ModelDeployment(Deployment, discriminator="ModelDeployment"): - """Model Deployment Definition. - - :ivar name: Name of the deployment. Required. - :vartype name: str - :ivar type: The type of the deployment. Required. Model deployment. - :vartype type: str or ~azure.ai.projects.models.MODEL_DEPLOYMENT - :ivar model_name: Publisher-specific name of the deployed model. Required. - :vartype model_name: str - :ivar model_version: Publisher-specific version of the deployed model. Required. - :vartype model_version: str - :ivar model_publisher: Name of the deployed model's publisher. Required. - :vartype model_publisher: str - :ivar capabilities: Capabilities of deployed model. Required. - :vartype capabilities: dict[str, str] - :ivar sku: Sku of the model deployment. Required. - :vartype sku: ~azure.ai.projects.models.ModelDeploymentSku - :ivar connection_name: Name of the connection the deployment comes from. - :vartype connection_name: str - """ +class OpenApiAnonymousAuthDetails(OpenApiAuthDetails, discriminator="anonymous"): + """Security details for OpenApi anonymous authentication. - type: Literal[DeploymentType.MODEL_DEPLOYMENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the deployment. Required. Model deployment.""" - model_name: str = rest_field(name="modelName", visibility=["read"]) - """Publisher-specific name of the deployed model. Required.""" - model_version: str = rest_field(name="modelVersion", visibility=["read"]) - """Publisher-specific version of the deployed model. Required.""" - model_publisher: str = rest_field(name="modelPublisher", visibility=["read"]) - """Name of the deployed model's publisher. Required.""" - capabilities: dict[str, str] = rest_field(visibility=["read"]) - """Capabilities of deployed model. Required.""" - sku: "_models.ModelDeploymentSku" = rest_field(visibility=["read"]) - """Sku of the model deployment. Required.""" - connection_name: Optional[str] = rest_field(name="connectionName", visibility=["read"]) - """Name of the connection the deployment comes from.""" + :ivar type: The object type, which is always 'anonymous'. Required. ANONYMOUS. + :vartype type: str or ~azure.ai.projects.models.ANONYMOUS + """ + + type: Literal[OpenApiAuthType.ANONYMOUS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The object type, which is always 'anonymous'. Required. ANONYMOUS.""" @overload def __init__( @@ -7377,44 +10352,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DeploymentType.MODEL_DEPLOYMENT # type: ignore + self.type = OpenApiAuthType.ANONYMOUS # type: ignore -class ModelDeploymentSku(_Model): - """Sku information. +class OpenApiFunctionDefinition(_Model): + """The input definition information for an openapi function. - :ivar capacity: Sku capacity. Required. - :vartype capacity: int - :ivar family: Sku family. Required. - :vartype family: str - :ivar name: Sku name. Required. + :ivar name: The name of the function to be called. Required. :vartype name: str - :ivar size: Sku size. Required. - :vartype size: str - :ivar tier: Sku tier. Required. - :vartype tier: str + :ivar description: A description of what the function does, used by the model to choose when + and how to call the function. + :vartype description: str + :ivar spec: The openapi function shape, described as a JSON Schema object. Required. + :vartype spec: dict[str, any] + :ivar auth: Open API authentication details. Required. + :vartype auth: ~azure.ai.projects.models.OpenApiAuthDetails + :ivar default_params: List of OpenAPI spec parameters that will use user-provided defaults. + :vartype default_params: list[str] + :ivar functions: List of function definitions used by OpenApi tool. + :vartype functions: list[~azure.ai.projects.models.OpenApiFunctionDefinitionFunction] """ - capacity: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Sku capacity. Required.""" - family: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Sku family. Required.""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Sku name. Required.""" - size: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Sku size. Required.""" - tier: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Sku tier. Required.""" + """The name of the function to be called. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description of what the function does, used by the model to choose when and how to call the + function.""" + spec: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The openapi function shape, described as a JSON Schema object. Required.""" + auth: "_models.OpenApiAuthDetails" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Open API authentication details. Required.""" + default_params: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """List of OpenAPI spec parameters that will use user-provided defaults.""" + functions: Optional[list["_models.OpenApiFunctionDefinitionFunction"]] = rest_field(visibility=["read"]) + """List of function definitions used by OpenApi tool.""" @overload def __init__( self, *, - capacity: int, - family: str, name: str, - size: str, - tier: str, + spec: dict[str, Any], + auth: "_models.OpenApiAuthDetails", + description: Optional[str] = None, + default_params: Optional[list[str]] = None, ) -> None: ... @overload @@ -7428,37 +10409,34 @@ 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. +class OpenApiFunctionDefinitionFunction(_Model): + """OpenApiFunctionDefinitionFunction. - :ivar temperature: The temperature parameter for sampling. Required. - :vartype temperature: float - :ivar top_p: The top-p parameter for nucleus sampling. Required. - :vartype top_p: float - :ivar seed: The random seed for reproducibility. Required. - :vartype seed: int - :ivar max_completion_tokens: The maximum number of tokens allowed in the completion. Required. - :vartype max_completion_tokens: int + :ivar name: The name of the function to be called. Required. + :vartype name: str + :ivar description: A description of what the function does, used by the model to choose when + and how to call the function. + :vartype description: str + :ivar parameters: The parameters the functions accepts, described as a JSON Schema object. + Required. + :vartype parameters: dict[str, any] """ - temperature: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The temperature parameter for sampling. Required.""" - top_p: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The top-p parameter for nucleus sampling. Required.""" - seed: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The random seed for reproducibility. Required.""" - max_completion_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The maximum number of tokens allowed in the completion. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function to be called. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description of what the function does, used by the model to choose when and how to call the + function.""" + parameters: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The parameters the functions accepts, described as a JSON Schema object. Required.""" @overload def __init__( self, *, - temperature: float, - top_p: float, - seed: int, - max_completion_tokens: int, + name: str, + parameters: dict[str, Any], + description: Optional[str] = None, ) -> None: ... @overload @@ -7472,27 +10450,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MonthlyRecurrenceSchedule(RecurrenceSchedule, discriminator="Monthly"): - """Monthly recurrence schedule. +class OpenApiManagedAuthDetails(OpenApiAuthDetails, discriminator="managed_identity"): + """Security details for OpenApi managed_identity authentication. - :ivar type: Monthly recurrence type. Required. Monthly recurrence pattern. - :vartype type: str or ~azure.ai.projects.models.MONTHLY - :ivar days_of_month: Days of the month for the recurrence schedule. Required. - :vartype days_of_month: list[int] + :ivar type: The object type, which is always 'managed_identity'. Required. MANAGED_IDENTITY. + :vartype type: str or ~azure.ai.projects.models.MANAGED_IDENTITY + :ivar security_scheme: Connection auth security details. Required. + :vartype security_scheme: ~azure.ai.projects.models.OpenApiManagedSecurityScheme """ - type: Literal[RecurrenceType.MONTHLY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Monthly recurrence type. Required. Monthly recurrence pattern.""" - days_of_month: list[int] = rest_field( - name="daysOfMonth", visibility=["read", "create", "update", "delete", "query"] + type: Literal[OpenApiAuthType.MANAGED_IDENTITY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The object type, which is always 'managed_identity'. Required. MANAGED_IDENTITY.""" + security_scheme: "_models.OpenApiManagedSecurityScheme" = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Days of the month for the recurrence schedule. Required.""" + """Connection auth security details. Required.""" @overload def __init__( self, *, - days_of_month: list[int], + security_scheme: "_models.OpenApiManagedSecurityScheme", ) -> None: ... @overload @@ -7504,22 +10482,24 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RecurrenceType.MONTHLY # type: ignore + self.type = OpenApiAuthType.MANAGED_IDENTITY # type: ignore -class NoAuthenticationCredentials(BaseCredentials, discriminator="None"): - """Credentials that do not require authentication. +class OpenApiManagedSecurityScheme(_Model): + """Security scheme for OpenApi managed_identity authentication. - :ivar type: The credential type. Required. No credential. - :vartype type: str or ~azure.ai.projects.models.NONE + :ivar audience: Authentication scope for managed_identity auth type. Required. + :vartype audience: str """ - type: Literal[CredentialType.NONE] = rest_discriminator(name="type", visibility=["read"]) # type: ignore - """The credential type. Required. No credential.""" + audience: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Authentication scope for managed_identity auth type. Required.""" @overload def __init__( self, + *, + audience: str, ) -> None: ... @overload @@ -7531,35 +10511,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = CredentialType.NONE # type: ignore -class OneTimeTrigger(Trigger, discriminator="OneTime"): - """One-time trigger. +class OpenApiProjectConnectionAuthDetails(OpenApiAuthDetails, discriminator="project_connection"): + """Security details for OpenApi project connection authentication. - :ivar type: Required. One-time trigger. - :vartype type: str or ~azure.ai.projects.models.ONE_TIME - :ivar trigger_at: Date and time for the one-time trigger in ISO 8601 format. Required. - :vartype trigger_at: ~datetime.datetime - :ivar time_zone: Time zone for the one-time trigger. - :vartype time_zone: str + :ivar type: The object type, which is always 'project_connection'. Required. + PROJECT_CONNECTION. + :vartype type: str or ~azure.ai.projects.models.PROJECT_CONNECTION + :ivar security_scheme: Project connection auth security details. Required. + :vartype security_scheme: ~azure.ai.projects.models.OpenApiProjectConnectionSecurityScheme """ - type: Literal[TriggerType.ONE_TIME] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. One-time trigger.""" - trigger_at: datetime.datetime = rest_field( - name="triggerAt", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + type: Literal[OpenApiAuthType.PROJECT_CONNECTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The object type, which is always 'project_connection'. Required. PROJECT_CONNECTION.""" + security_scheme: "_models.OpenApiProjectConnectionSecurityScheme" = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Date and time for the one-time trigger in ISO 8601 format. Required.""" - time_zone: Optional[str] = rest_field(name="timeZone", visibility=["read", "create", "update", "delete", "query"]) - """Time zone for the one-time trigger.""" + """Project connection auth security details. Required.""" @overload def __init__( self, *, - trigger_at: datetime.datetime, - time_zone: Optional[str] = None, + security_scheme: "_models.OpenApiProjectConnectionSecurityScheme", ) -> None: ... @overload @@ -7571,30 +10546,24 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TriggerType.ONE_TIME # type: ignore - + self.type = OpenApiAuthType.PROJECT_CONNECTION # type: ignore -class OpenApiAuthDetails(_Model): - """authentication details for OpenApiFunctionDefinition. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - OpenApiAnonymousAuthDetails, OpenApiManagedAuthDetails, OpenApiProjectConnectionAuthDetails +class OpenApiProjectConnectionSecurityScheme(_Model): + """Security scheme for OpenApi managed_identity authentication. - :ivar type: The type of authentication, must be anonymous/project_connection/managed_identity. - Required. Known values are: "anonymous", "project_connection", and "managed_identity". - :vartype type: str or ~azure.ai.projects.models.OpenApiAuthType + :ivar project_connection_id: Project connection id for Project Connection auth type. Required. + :vartype project_connection_id: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of authentication, must be anonymous/project_connection/managed_identity. Required. - Known values are: \"anonymous\", \"project_connection\", and \"managed_identity\".""" + project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Project connection id for Project Connection auth type. Required.""" @overload def __init__( self, *, - type: str, + project_connection_id: str, ) -> None: ... @overload @@ -7608,19 +10577,38 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiAnonymousAuthDetails(OpenApiAuthDetails, discriminator="anonymous"): - """Security details for OpenApi anonymous authentication. +class OpenApiTool(Tool, discriminator="openapi"): + """The input definition information for an OpenAPI tool as used to configure an agent. - :ivar type: The object type, which is always 'anonymous'. Required. ANONYMOUS. - :vartype type: str or ~azure.ai.projects.models.ANONYMOUS + :ivar type: The object type, which is always 'openapi'. Required. OPENAPI. + :vartype type: str or ~azure.ai.projects.models.OPENAPI + :ivar openapi: The openapi function definition. Required. + :vartype openapi: ~azure.ai.projects.models.OpenApiFunctionDefinition + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] """ - type: Literal[OpenApiAuthType.ANONYMOUS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The object type, which is always 'anonymous'. Required. ANONYMOUS.""" + type: Literal[ToolType.OPENAPI] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The object type, which is always 'openapi'. Required. OPENAPI.""" + openapi: "_models.OpenApiFunctionDefinition" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The openapi function definition. Required.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" @overload def __init__( self, + *, + openapi: "_models.OpenApiFunctionDefinition", + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -7632,50 +10620,85 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = OpenApiAuthType.ANONYMOUS # type: ignore + self.type = ToolType.OPENAPI # type: ignore -class OpenApiFunctionDefinition(_Model): - """The input definition information for an openapi function. +class OptimizationAgentDefinition(_Model): + """The agent definition being optimized. Identifies the Foundry agent and optional configuration + overrides. - :ivar name: The name of the function to be called. Required. - :vartype name: str - :ivar description: A description of what the function does, used by the model to choose when - and how to call the function. - :vartype description: str - :ivar spec: The openapi function shape, described as a JSON Schema object. Required. - :vartype spec: dict[str, any] - :ivar auth: Open API authentication details. Required. - :vartype auth: ~azure.ai.projects.models.OpenApiAuthDetails - :ivar default_params: List of OpenAPI spec parameters that will use user-provided defaults. - :vartype default_params: list[str] - :ivar functions: List of function definitions used by OpenApi tool. - :vartype functions: list[~azure.ai.projects.models.OpenApiFunctionDefinitionFunction] + :ivar agent_name: Registered Foundry agent name. Required — bare-model mode is not supported. + Required. + :vartype agent_name: str + :ivar agent_version: Pinned agent version. Defaults to latest if omitted. + :vartype agent_version: str + :ivar model: Model deployment name (e.g., 'gpt-4o'). Optional when agent_name is set — the + agent definition provides the model. + :vartype model: str + :ivar system_prompt: System prompt / instructions override. When set, used as the baseline + instructions for the agent. + :vartype system_prompt: str + :ivar skills: Optional named skills the optimizer may tune. Tool descriptions and parameters. + :vartype skills: list[~azure.ai.projects.models.OptimizationAgentSkill] """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function to be called. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A description of what the function does, used by the model to choose when and how to call the - function.""" - spec: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The openapi function shape, described as a JSON Schema object. Required.""" - auth: "_models.OpenApiAuthDetails" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Open API authentication details. Required.""" - default_params: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """List of OpenAPI spec parameters that will use user-provided defaults.""" - functions: Optional[list["_models.OpenApiFunctionDefinitionFunction"]] = rest_field(visibility=["read"]) - """List of function definitions used by OpenApi tool.""" + agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Registered Foundry agent name. Required — bare-model mode is not supported. Required.""" + agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Pinned agent version. Defaults to latest if omitted.""" + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Model deployment name (e.g., 'gpt-4o'). Optional when agent_name is set — the agent definition + provides the model.""" + system_prompt: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """System prompt / instructions override. When set, used as the baseline instructions for the + agent.""" + skills: Optional[list["_models.OptimizationAgentSkill"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional named skills the optimizer may tune. Tool descriptions and parameters.""" + + @overload + def __init__( + self, + *, + agent_name: str, + agent_version: Optional[str] = None, + model: Optional[str] = None, + system_prompt: Optional[str] = None, + skills: Optional[list["_models.OptimizationAgentSkill"]] = 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 OptimizationAgentSkill(_Model): + """A named skill on the agent that the optimizer may tune. + + :ivar name: Skill name (matches the tool name on the agent). Required. + :vartype name: str + :ivar description: Free-form description used as the seed when tuning skill descriptions. + :vartype description: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Skill name (matches the tool name on the agent). Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Free-form description used as the seed when tuning skill descriptions.""" @overload def __init__( self, *, name: str, - spec: dict[str, Any], - auth: "_models.OpenApiAuthDetails", description: Optional[str] = None, - default_params: Optional[list[str]] = None, ) -> None: ... @overload @@ -7689,34 +10712,108 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiFunctionDefinitionFunction(_Model): - """OpenApiFunctionDefinitionFunction. +class OptimizationCandidate(_Model): + """Aggregated evaluation result for a single candidate agent configuration across all tasks. - :ivar name: The name of the function to be called. Required. + :ivar candidate_id: Server-assigned candidate identifier. Use with ``GET /candidates/{id}`` + sub-endpoints. + :vartype candidate_id: str + :ivar name: Display name of the candidate (e.g., 'baseline', 'instruction-v2'). Required. :vartype name: str - :ivar description: A description of what the function does, used by the model to choose when - and how to call the function. - :vartype description: str - :ivar parameters: The parameters the functions accepts, described as a JSON Schema object. + :ivar config: The agent configuration that produced this candidate. Required. + :vartype config: ~azure.ai.projects.models.OptimizationAgentDefinition + :ivar mutations: What was mutated from the baseline (e.g., {instructions: 'new prompt'}). Required. - :vartype parameters: dict[str, any] + :vartype mutations: dict[str, any] + :ivar rationale: Strategy rationale — why this candidate was generated. Required. + :vartype rationale: str + :ivar avg_score: Average composite score across all tasks. Required. + :vartype avg_score: float + :ivar avg_tokens: Average token usage across all tasks. Required. + :vartype avg_tokens: float + :ivar pass_rate: Fraction of tasks that met the pass threshold. Required. + :vartype pass_rate: float + :ivar task_scores: Individual task-level scores. Required. + :vartype task_scores: list[~azure.ai.projects.models.OptimizationTaskResult] + :ivar is_pareto_optimal: Whether this candidate is on the Pareto frontier (score vs cost). + Required. + :vartype is_pareto_optimal: bool + :ivar sample_avg_score: Average score from sampled evaluation (null if full dataset was used). + :vartype sample_avg_score: float + :ivar sample_size: Number of tasks in the sample (null if full dataset was used). + :vartype sample_size: int + :ivar evaluation_type: 'sample' if scored on a subset, 'full' if re-evaluated on the full + dataset. + :vartype evaluation_type: str + :ivar strategy: Identifies the strategy that produced this candidate. Known values are: + "instruction", "model", and "skill". + :vartype strategy: str or ~azure.ai.projects.models.OptimizationStrategy + :ivar eval_id: Foundry evaluation identifier used to score this candidate. + :vartype eval_id: str + :ivar eval_run_id: Foundry evaluation run identifier for this candidate's scoring run. + :vartype eval_run_id: str """ + candidate_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Server-assigned candidate identifier. Use with ``GET /candidates/{id}`` sub-endpoints.""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function to be called. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A description of what the function does, used by the model to choose when and how to call the - function.""" - parameters: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The parameters the functions accepts, described as a JSON Schema object. Required.""" + """Display name of the candidate (e.g., 'baseline', 'instruction-v2'). Required.""" + config: "_models.OptimizationAgentDefinition" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The agent configuration that produced this candidate. Required.""" + mutations: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """What was mutated from the baseline (e.g., {instructions: 'new prompt'}). Required.""" + rationale: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Strategy rationale — why this candidate was generated. Required.""" + avg_score: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Average composite score across all tasks. Required.""" + avg_tokens: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Average token usage across all tasks. Required.""" + pass_rate: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Fraction of tasks that met the pass threshold. Required.""" + task_scores: list["_models.OptimizationTaskResult"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Individual task-level scores. Required.""" + is_pareto_optimal: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether this candidate is on the Pareto frontier (score vs cost). Required.""" + sample_avg_score: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Average score from sampled evaluation (null if full dataset was used).""" + sample_size: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of tasks in the sample (null if full dataset was used).""" + evaluation_type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """'sample' if scored on a subset, 'full' if re-evaluated on the full dataset.""" + strategy: Optional[Union[str, "_models.OptimizationStrategy"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Identifies the strategy that produced this candidate. Known values are: \"instruction\", + \"model\", and \"skill\".""" + eval_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Foundry evaluation identifier used to score this candidate.""" + eval_run_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Foundry evaluation run identifier for this candidate's scoring run.""" @overload def __init__( self, *, name: str, - parameters: dict[str, Any], - description: Optional[str] = None, + config: "_models.OptimizationAgentDefinition", + mutations: dict[str, Any], + rationale: str, + avg_score: float, + avg_tokens: float, + pass_rate: float, + task_scores: list["_models.OptimizationTaskResult"], + is_pareto_optimal: bool, + candidate_id: Optional[str] = None, + sample_avg_score: Optional[float] = None, + sample_size: Optional[int] = None, + evaluation_type: Optional[str] = None, + strategy: Optional[Union[str, "_models.OptimizationStrategy"]] = None, + eval_id: Optional[str] = None, + eval_run_id: Optional[str] = None, ) -> None: ... @overload @@ -7730,27 +10827,55 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiManagedAuthDetails(OpenApiAuthDetails, discriminator="managed_identity"): - """Security details for OpenApi managed_identity authentication. +class OptimizationJob(_Model): + """Agent optimization job resource — a long-running job that optimizes an agent's configuration + (instructions, model, skills) to maximize evaluation scores. On success, the result contains + scored candidates. - :ivar type: The object type, which is always 'managed_identity'. Required. MANAGED_IDENTITY. - :vartype type: str or ~azure.ai.projects.models.MANAGED_IDENTITY - :ivar security_scheme: Connection auth security details. Required. - :vartype security_scheme: ~azure.ai.projects.models.OpenApiManagedSecurityScheme + :ivar id: Server-assigned unique identifier. Required. + :vartype id: str + :ivar inputs: Caller-supplied inputs. + :vartype inputs: ~azure.ai.projects.models.OptimizationJobInputs + :ivar result: Result produced on success. + :vartype result: ~azure.ai.projects.models.OptimizationJobResult + :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. Required. + :vartype created_at: ~datetime.datetime + :ivar updated_at: The timestamp when the job was last updated, represented in Unix time. + :vartype updated_at: ~datetime.datetime + :ivar progress: Progress while in flight. Absent in terminal states. + :vartype progress: ~azure.ai.projects.models.OptimizationJobProgress """ - type: Literal[OpenApiAuthType.MANAGED_IDENTITY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The object type, which is always 'managed_identity'. Required. MANAGED_IDENTITY.""" - security_scheme: "_models.OpenApiManagedSecurityScheme" = rest_field( + id: str = rest_field(visibility=["read"]) + """Server-assigned unique identifier. Required.""" + inputs: Optional["_models.OptimizationJobInputs"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Connection auth security details. Required.""" + """Caller-supplied inputs.""" + result: Optional["_models.OptimizationJobResult"] = 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. Required.""" + updated_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The timestamp when the job was last updated, represented in Unix time.""" + progress: Optional["_models.OptimizationJobProgress"] = rest_field(visibility=["read"]) + """Progress while in flight. Absent in terminal states.""" @overload def __init__( self, *, - security_scheme: "_models.OpenApiManagedSecurityScheme", + inputs: Optional["_models.OptimizationJobInputs"] = None, ) -> None: ... @overload @@ -7762,24 +10887,70 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = OpenApiAuthType.MANAGED_IDENTITY # type: ignore -class OpenApiManagedSecurityScheme(_Model): - """Security scheme for OpenApi managed_identity authentication. +class OptimizationJobInputs(_Model): + """Caller-supplied inputs for an optimization job. - :ivar audience: Authentication scope for managed_identity auth type. Required. - :vartype audience: str + :ivar agent: The agent (and pinned version) being optimized. Required. + :vartype agent: ~azure.ai.projects.models.OptimizationAgentDefinition + :ivar dataset: Inline evaluation dataset. Mutually exclusive with ``train_dataset_reference``. + :vartype dataset: list[~azure.ai.projects.models.DatasetItem] + :ivar train_dataset_reference: Reference to a registered training dataset. Mutually exclusive + with ``dataset``. + :vartype train_dataset_reference: ~azure.ai.projects.models.DatasetRef + :ivar validation_dataset_reference: Optional held-out validation dataset for measuring + generalization of the final candidate. + :vartype validation_dataset_reference: ~azure.ai.projects.models.DatasetRef + :ivar evaluators: Job-level evaluators (referenced by ``name``). Per-task ``criteria`` may + override. Default: ['task_adherence']. + :vartype evaluators: list[str] + :ivar criteria: Job-level evaluation criteria. Applied to all tasks unless overridden by + per-task ``criteria``. + :vartype criteria: list[~azure.ai.projects.models.EvaluationCriterion] + :ivar options: Tuning knobs and run-mode. + :vartype options: ~azure.ai.projects.models.OptimizationOptions """ - audience: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Authentication scope for managed_identity auth type. Required.""" + agent: "_models.OptimizationAgentDefinition" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The agent (and pinned version) being optimized. Required.""" + dataset: Optional[list["_models.DatasetItem"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Inline evaluation dataset. Mutually exclusive with ``train_dataset_reference``.""" + train_dataset_reference: Optional["_models.DatasetRef"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Reference to a registered training dataset. Mutually exclusive with ``dataset``.""" + validation_dataset_reference: Optional["_models.DatasetRef"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional held-out validation dataset for measuring generalization of the final candidate.""" + evaluators: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Job-level evaluators (referenced by ``name``). Per-task ``criteria`` may override. Default: + ['task_adherence'].""" + criteria: Optional[list["_models.EvaluationCriterion"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Job-level evaluation criteria. Applied to all tasks unless overridden by per-task ``criteria``.""" + options: Optional["_models.OptimizationOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Tuning knobs and run-mode.""" @overload def __init__( self, *, - audience: str, + agent: "_models.OptimizationAgentDefinition", + dataset: Optional[list["_models.DatasetItem"]] = None, + train_dataset_reference: Optional["_models.DatasetRef"] = None, + validation_dataset_reference: Optional["_models.DatasetRef"] = None, + evaluators: Optional[list[str]] = None, + criteria: Optional[list["_models.EvaluationCriterion"]] = None, + options: Optional["_models.OptimizationOptions"] = None, ) -> None: ... @overload @@ -7793,28 +10964,50 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiProjectConnectionAuthDetails(OpenApiAuthDetails, discriminator="project_connection"): - """Security details for OpenApi project connection authentication. +class OptimizationJobProgress(_Model): + """In-flight progress; only populated while status is ``queued`` or ``in_progress``. - :ivar type: The object type, which is always 'project_connection'. Required. - PROJECT_CONNECTION. - :vartype type: str or ~azure.ai.projects.models.PROJECT_CONNECTION - :ivar security_scheme: Project connection auth security details. Required. - :vartype security_scheme: ~azure.ai.projects.models.OpenApiProjectConnectionSecurityScheme + :ivar current_strategy: Strategy currently being explored. Required. Known values are: + "instruction", "model", and "skill". + :vartype current_strategy: str or ~azure.ai.projects.models.OptimizationStrategy + :ivar current_iteration: 1-based current iteration index. Required. + :vartype current_iteration: int + :ivar tasks_completed: Tasks evaluated so far this iteration. Required. + :vartype tasks_completed: int + :ivar tasks_total: Total tasks scheduled this iteration. Required. + :vartype tasks_total: int + :ivar best_score: Best score observed so far across all candidates. Required. + :vartype best_score: float + :ivar elapsed_seconds: Wall-clock time elapsed since the job began executing. Required. + :vartype elapsed_seconds: float """ - type: Literal[OpenApiAuthType.PROJECT_CONNECTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The object type, which is always 'project_connection'. Required. PROJECT_CONNECTION.""" - security_scheme: "_models.OpenApiProjectConnectionSecurityScheme" = rest_field( + current_strategy: Union[str, "_models.OptimizationStrategy"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Project connection auth security details. Required.""" + """Strategy currently being explored. Required. Known values are: \"instruction\", \"model\", and + \"skill\".""" + current_iteration: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """1-based current iteration index. Required.""" + tasks_completed: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Tasks evaluated so far this iteration. Required.""" + tasks_total: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total tasks scheduled this iteration. Required.""" + best_score: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Best score observed so far across all candidates. Required.""" + elapsed_seconds: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Wall-clock time elapsed since the job began executing. Required.""" @overload def __init__( self, *, - security_scheme: "_models.OpenApiProjectConnectionSecurityScheme", + current_strategy: Union[str, "_models.OptimizationStrategy"], + current_iteration: int, + tasks_completed: int, + tasks_total: int, + best_score: float, + elapsed_seconds: float, ) -> None: ... @overload @@ -7826,24 +11019,80 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = OpenApiAuthType.PROJECT_CONNECTION # type: ignore -class OpenApiProjectConnectionSecurityScheme(_Model): - """Security scheme for OpenApi managed_identity authentication. +class OptimizationJobResult(_Model): + """Terminal-state result body. Populated when ``status`` is ``succeeded`` or ``failed``. - :ivar project_connection_id: Project connection id for Project Connection auth type. Required. - :vartype project_connection_id: str + :ivar baseline: Evaluation scores for the original (un-optimized) agent configuration. + :vartype baseline: ~azure.ai.projects.models.OptimizationCandidate + :ivar best: The highest-scoring candidate found during optimization. + :vartype best: ~azure.ai.projects.models.OptimizationCandidate + :ivar candidates: All evaluated candidates including baseline. + :vartype candidates: list[~azure.ai.projects.models.OptimizationCandidate] + :ivar pareto_frontier: Candidates on the Pareto frontier (maximize score, minimize cost). + :vartype pareto_frontier: list[~azure.ai.projects.models.OptimizationCandidate] + :ivar validation_score: Score of the best candidate on the held-out validation dataset. Null + when no validation dataset was provided. + :vartype validation_score: ~azure.ai.projects.models.OptimizationCandidate + :ivar options: The options used for this optimization run. + :vartype options: ~azure.ai.projects.models.OptimizationOptions + :ivar sample_size: Number of tasks sampled during optimization iterations (null if sampling was + not used). + :vartype sample_size: int + :ivar warnings: Non-fatal warnings from the optimization run (e.g., strategy failures that were + skipped). + :vartype warnings: list[str] + :ivar all_strategies_failed: True when all optimization strategies failed — only the baseline + was evaluated. + :vartype all_strategies_failed: bool """ - project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Project connection id for Project Connection auth type. Required.""" + baseline: Optional["_models.OptimizationCandidate"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Evaluation scores for the original (un-optimized) agent configuration.""" + best: Optional["_models.OptimizationCandidate"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The highest-scoring candidate found during optimization.""" + candidates: Optional[list["_models.OptimizationCandidate"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """All evaluated candidates including baseline.""" + pareto_frontier: Optional[list["_models.OptimizationCandidate"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Candidates on the Pareto frontier (maximize score, minimize cost).""" + validation_score: Optional["_models.OptimizationCandidate"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Score of the best candidate on the held-out validation dataset. Null when no validation dataset + was provided.""" + options: Optional["_models.OptimizationOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The options used for this optimization run.""" + sample_size: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of tasks sampled during optimization iterations (null if sampling was not used).""" + warnings: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Non-fatal warnings from the optimization run (e.g., strategy failures that were skipped).""" + all_strategies_failed: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """True when all optimization strategies failed — only the baseline was evaluated.""" @overload def __init__( self, *, - project_connection_id: str, + baseline: Optional["_models.OptimizationCandidate"] = None, + best: Optional["_models.OptimizationCandidate"] = None, + candidates: Optional[list["_models.OptimizationCandidate"]] = None, + pareto_frontier: Optional[list["_models.OptimizationCandidate"]] = None, + validation_score: Optional["_models.OptimizationCandidate"] = None, + options: Optional["_models.OptimizationOptions"] = None, + sample_size: Optional[int] = None, + warnings: Optional[list[str]] = None, + all_strategies_failed: Optional[bool] = None, ) -> None: ... @overload @@ -7857,27 +11106,173 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiTool(Tool, discriminator="openapi"): - """The input definition information for an OpenAPI tool as used to configure an agent. - - :ivar type: The object type, which is always 'openapi'. Required. OPENAPI. - :vartype type: str or ~azure.ai.projects.models.OPENAPI - :ivar openapi: The openapi function definition. Required. - :vartype openapi: ~azure.ai.projects.models.OpenApiFunctionDefinition - """ +class OptimizationOptions(_Model): + """Tuning knobs and run-mode for an optimization job. - type: Literal[ToolType.OPENAPI] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The object type, which is always 'openapi'. Required. OPENAPI.""" - openapi: "_models.OpenApiFunctionDefinition" = rest_field( + :ivar strategies: Strategies to apply this run. Default: ['instruction']. + :vartype strategies: list[str or ~azure.ai.projects.models.OptimizationStrategy] + :ivar budget: Total candidate generation budget (number of candidates explored). Default: 10. + :vartype budget: int + :ivar max_iterations: Maximum optimization iterations per strategy. Default: 5. + :vartype max_iterations: int + :ivar tasks_per_iteration: Tasks sampled per iteration (mutation step input). Default: + service-decided (auto-computed). + :vartype tasks_per_iteration: int + :ivar max_reflection_tasks: Maximum tasks fed into the reflective-mutation LLM per iteration. + Default: 5. + :vartype max_reflection_tasks: int + :ivar min_improvement: Minimum score improvement between iterations to continue (plateau + detection). Default: 0.005. + :vartype min_improvement: float + :ivar pass_threshold: Composite score threshold for a task to be considered passing. Default: + 0.5. + :vartype pass_threshold: float + :ivar improvement_threshold: Target average score at which optimization stops early (quality + ceiling). Default: 0.95. + :vartype improvement_threshold: float + :ivar mode: Run mode. "optimize" + :vartype mode: str or ~azure.ai.projects.models.OptimizationMode + :ivar eval_model: Foundry deployment name to use as the LLM-as-judge evaluation model. + Required. + :vartype eval_model: str + :ivar reflection_model: Optional model deployment for strategy reflection (instruction + rewriting, skill generation). Falls back to ``eval_model`` if unset. + :vartype reflection_model: str + :ivar task_timeout_seconds: Per-task timeout for agent execution. Default: 300 seconds (5 + minutes). + :vartype task_timeout_seconds: int + :ivar keep_versions: If true, retain temporary candidate-evaluation agent versions for + inspection. Default: false. + :vartype keep_versions: bool + """ + + strategies: Optional[list[Union[str, "_models.OptimizationStrategy"]]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The openapi function definition. Required.""" + """Strategies to apply this run. Default: ['instruction'].""" + budget: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total candidate generation budget (number of candidates explored). Default: 10.""" + max_iterations: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum optimization iterations per strategy. Default: 5.""" + tasks_per_iteration: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Tasks sampled per iteration (mutation step input). Default: service-decided (auto-computed).""" + max_reflection_tasks: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum tasks fed into the reflective-mutation LLM per iteration. Default: 5.""" + min_improvement: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Minimum score improvement between iterations to continue (plateau detection). Default: 0.005.""" + pass_threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Composite score threshold for a task to be considered passing. Default: 0.5.""" + improvement_threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Target average score at which optimization stops early (quality ceiling). Default: 0.95.""" + mode: Optional[Union[str, "_models.OptimizationMode"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Run mode. \"optimize\"""" + eval_model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Foundry deployment name to use as the LLM-as-judge evaluation model. Required.""" + reflection_model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional model deployment for strategy reflection (instruction rewriting, skill generation). + Falls back to ``eval_model`` if unset.""" + task_timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Per-task timeout for agent execution. Default: 300 seconds (5 minutes).""" + keep_versions: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """If true, retain temporary candidate-evaluation agent versions for inspection. Default: false.""" @overload def __init__( self, *, - openapi: "_models.OpenApiFunctionDefinition", + strategies: Optional[list[Union[str, "_models.OptimizationStrategy"]]] = None, + budget: Optional[int] = None, + max_iterations: Optional[int] = None, + tasks_per_iteration: Optional[int] = None, + max_reflection_tasks: Optional[int] = None, + min_improvement: Optional[float] = None, + pass_threshold: Optional[float] = None, + improvement_threshold: Optional[float] = None, + mode: Optional[Union[str, "_models.OptimizationMode"]] = None, + eval_model: Optional[str] = None, + reflection_model: Optional[str] = None, + task_timeout_seconds: Optional[int] = None, + keep_versions: 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 OptimizationTaskResult(_Model): + """Per-task evaluation result for a single candidate. + + :ivar task_name: Task name (from the dataset). Required. + :vartype task_name: str + :ivar query: The user query / input for the task. + :vartype query: str + :ivar scores: Per-evaluator scores keyed by evaluator name. Required. + :vartype scores: dict[str, float] + :ivar composite_score: Composite score combining all evaluator scores. Required. + :vartype composite_score: float + :ivar tokens: Total tokens consumed during the agent run for this task. Required. + :vartype tokens: int + :ivar duration_seconds: Wall-clock seconds for this task's agent execution. Required. + :vartype duration_seconds: float + :ivar passed: Whether the task met the pass threshold. Required. + :vartype passed: bool + :ivar error_message: Error message if the task failed during execution. + :vartype error_message: str + :ivar rationales: Per-evaluator reasoning keyed by evaluator name. + :vartype rationales: dict[str, str] + :ivar response: Raw agent response text. + :vartype response: str + :ivar run_id: Identifier of the agent run that produced this result. + :vartype run_id: str + """ + + task_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Task name (from the dataset). Required.""" + query: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The user query / input for the task.""" + scores: dict[str, float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Per-evaluator scores keyed by evaluator name. Required.""" + composite_score: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Composite score combining all evaluator scores. Required.""" + tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total tokens consumed during the agent run for this task. Required.""" + duration_seconds: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Wall-clock seconds for this task's agent execution. Required.""" + passed: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the task met the pass threshold. Required.""" + error_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Error message if the task failed during execution.""" + rationales: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Per-evaluator reasoning keyed by evaluator name.""" + response: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Raw agent response text.""" + run_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier of the agent run that produced this result.""" + + @overload + def __init__( + self, + *, + task_name: str, + scores: dict[str, float], + composite_score: float, + tokens: int, + duration_seconds: float, + passed: bool, + query: Optional[str] = None, + error_message: Optional[str] = None, + rationales: Optional[dict[str, str]] = None, + response: Optional[str] = None, + run_id: Optional[str] = None, ) -> None: ... @overload @@ -7889,7 +11284,6 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.OPENAPI # type: ignore class TelemetryEndpoint(_Model): @@ -7998,8 +11392,8 @@ 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. + :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 """ @@ -8014,7 +11408,8 @@ class PendingUploadRequest(_Model): pending_upload_type: Literal[PendingUploadType.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.""" + """The type of pending upload. Required. Deprecated: the service never read this value and + silently ignored it. Use TemporaryBlobReference instead.""" @overload def __init__( @@ -8046,8 +11441,8 @@ class PendingUploadResponse(_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. + :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 """ @@ -8064,7 +11459,8 @@ class PendingUploadResponse(_Model): pending_upload_type: Literal[PendingUploadType.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.""" + """The type of pending upload. Required. Deprecated: the service never read this value and + silently ignored it. Use TemporaryBlobReference instead.""" @overload def __init__( @@ -8087,6 +11483,48 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class ProceduralMemoryItem(MemoryItem, discriminator="procedural"): + """A memory item containing a procedure extracted from conversations. + + :ivar memory_id: The unique ID of the memory item. Required. + :vartype memory_id: str + :ivar updated_at: The last update time of the memory item. Required. + :vartype updated_at: ~datetime.datetime + :ivar scope: The namespace that logically groups and isolates memories, such as a user ID. + Required. + :vartype scope: str + :ivar content: The content of the memory. Required. + :vartype content: str + :ivar kind: The kind of the memory item. Required. Routine procedures extracted from + conversations. + :vartype kind: str or ~azure.ai.projects.models.PROCEDURAL + """ + + kind: Literal[MemoryItemKind.PROCEDURAL] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The kind of the memory item. Required. Routine procedures extracted from conversations.""" + + @overload + def __init__( + self, + *, + memory_id: str, + updated_at: datetime.datetime, + scope: str, + content: 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.kind = MemoryItemKind.PROCEDURAL # type: ignore + + class PromptAgentDefinition(AgentDefinition, discriminator="prompt"): """The prompt agent definition. @@ -8100,14 +11538,13 @@ class PromptAgentDefinition(AgentDefinition, discriminator="prompt"): :vartype instructions: str :ivar temperature: What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and - deterministic. We generally recommend altering this or ``top_p`` but not both. + deterministic. We generally recommend altering this or ``top_p`` but not both. Defaults to + ``1``. :vartype temperature: float - :ivar top_p: An alternative to sampling with temperature, called nucleus sampling, - where the model considers the results of the tokens with top_p probability - mass. So 0.1 means only the tokens comprising the top 10% probability mass - are considered. - - We generally recommend altering this or ``temperature`` but not both. + :ivar top_p: An alternative to sampling with temperature, called nucleus sampling, where the + model considers the results of the tokens with top_p probability mass. So 0.1 means only the + tokens comprising the top 10% probability mass are considered. We generally recommend altering + this or ``temperature`` but not both. Defaults to ``1``. :vartype top_p: float :ivar reasoning: :vartype reasoning: ~azure.ai.projects.models.Reasoning @@ -8135,14 +11572,12 @@ class PromptAgentDefinition(AgentDefinition, discriminator="prompt"): temperature: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We - generally recommend altering this or ``top_p`` but not both.""" + generally recommend altering this or ``top_p`` but not both. Defaults to ``1``.""" top_p: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An alternative to sampling with temperature, called nucleus sampling, - where the model considers the results of the tokens with top_p probability - mass. So 0.1 means only the tokens comprising the top 10% probability mass - are considered. - - We generally recommend altering this or ``temperature`` but not both.""" + """An alternative to sampling with temperature, called nucleus sampling, where the model considers + the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising + the top 10% probability mass are considered. We generally recommend altering this or + ``temperature`` but not both. Defaults to ``1``.""" reasoning: Optional["_models.Reasoning"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) tools: Optional[list["_models.Tool"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """An array of tools the model may call while generating a response. You can specify which tool to @@ -8189,26 +11624,110 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = AgentKind.PROMPT # type: ignore + self.kind = AgentKind.PROMPT # type: ignore + + +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 PromptAgentDefinitionTextOptions(_Model): - """Configuration options for a text response from the model. Can be plain text or structured JSON - data. +class PromptDataGenerationJobSource(DataGenerationJobSource, discriminator="prompt"): + """Prompt source for data generation jobs — inline text provided by the user. - :ivar format: - :vartype format: ~azure.ai.projects.models.TextResponseFormat + :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 """ - format: Optional["_models.TextResponseFormat"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) + 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, *, - format: Optional["_models.TextResponseFormat"] = None, + prompt: str, + description: Optional[str] = None, ) -> None: ... @overload @@ -8220,38 +11739,39 @@ 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 PromptBasedEvaluatorDefinition(EvaluatorDefinition, discriminator="prompt"): - """Prompt-based evaluator. +class PromptEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="prompt"): + """Prompt source for evaluator generation jobs — 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. + :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_text: The prompt text used for evaluation. Required. - :vartype prompt_text: str + :ivar prompt: Inline prompt text (e.g., agent description, policy text, supplementary context). + Required. + :vartype prompt: 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.""" + 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_text: str, - init_parameters: Optional[dict[str, Any]] = None, - data_schema: Optional[dict[str, Any]] = None, - metrics: Optional[dict[str, "_models.EvaluatorMetric"]] = None, + prompt: str, + description: Optional[str] = None, ) -> None: ... @overload @@ -8263,14 +11783,14 @@ 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 = EvaluatorGenerationJobSourceType.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 @@ -8279,8 +11799,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.""" @@ -8436,7 +11956,7 @@ class RecurrenceTrigger(Trigger, discriminator="Recurrence"): :vartype start_time: ~datetime.datetime :ivar end_time: End time for the recurrence schedule in ISO 8601 format. :vartype end_time: ~datetime.datetime - :ivar time_zone: Time zone for the recurrence schedule. + :ivar time_zone: Time zone for the recurrence schedule. Defaults to ``UTC``. :vartype time_zone: str :ivar interval: Interval for the recurrence schedule. Required. :vartype interval: int @@ -8455,7 +11975,7 @@ class RecurrenceTrigger(Trigger, discriminator="Recurrence"): ) """End time for the recurrence schedule in ISO 8601 format.""" time_zone: Optional[str] = rest_field(name="timeZone", visibility=["read", "create", "update", "delete", "query"]) - """Time zone for the recurrence schedule.""" + """Time zone for the recurrence schedule. Defaults to ``UTC``.""" interval: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Interval for the recurrence schedule. Required.""" schedule: "_models.RecurrenceSchedule" = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -8511,7 +12031,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"]) @@ -8546,14 +12066,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, @@ -8631,6 +12151,303 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class Routine(_Model): + """A routine definition returned by the service. + + :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 + """ + + 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"] + ) + """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, + *, + 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 + 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 RoutineRun(_Model): + """A single routine run returned from the run history API. + + :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 + """ + + 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, + *, + 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 + 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.RUBRIC # type: ignore + + class SASCredentials(BaseCredentials, discriminator="SAS"): """Shared Access Signature (SAS) credential definition. @@ -8740,6 +12557,46 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class ScheduleRoutineTrigger(RoutineTrigger, discriminator="schedule"): + """A recurring cron-based routine trigger. + + :ivar type: The trigger type. Required. A recurring cron-based trigger. + :vartype type: str or ~azure.ai.projects.models.SCHEDULE + :ivar cron_expression: A 5-field cron expression. The service enforces a minimum interval of + five minutes by default. Required. + :vartype cron_expression: str + :ivar time_zone: An IANA or Windows time zone identifier for the schedule. Required. + :vartype time_zone: str + """ + + type: Literal[RoutineTriggerType.SCHEDULE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The trigger type. Required. A recurring cron-based trigger.""" + cron_expression: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A 5-field cron expression. The service enforces a minimum interval of five minutes by default. + Required.""" + time_zone: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An IANA or Windows time zone identifier for the schedule. Required.""" + + @overload + def __init__( + self, + *, + cron_expression: str, + time_zone: 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 = RoutineTriggerType.SCHEDULE # type: ignore + + class ScheduleRun(_Model): """Schedule run model. @@ -8836,7 +12693,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SessionDirectoryListResponse(_Model): +class SessionDirectoryListResult(_Model): """Response from listing a directory in a session sandbox. :ivar path: The path that was listed, relative to the session home directory. Required. @@ -8871,7 +12728,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SessionFileWriteResponse(_Model): +class SessionFileWriteResult(_Model): """Response from uploading a file to a session sandbox. :ivar path: The path where the file was written, relative to the session home directory. @@ -9001,6 +12858,14 @@ class SharepointPreviewTool(Tool, discriminator="sharepoint_grounding_preview"): :ivar type: The object type, which is always 'sharepoint_grounding_preview'. Required. SHAREPOINT_GROUNDING_PREVIEW. :vartype type: str or ~azure.ai.projects.models.SHAREPOINT_GROUNDING_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar sharepoint_grounding_preview: The sharepoint grounding tool parameters. Required. :vartype sharepoint_grounding_preview: ~azure.ai.projects.models.SharepointGroundingToolParameters @@ -9009,6 +12874,16 @@ class SharepointPreviewTool(Tool, discriminator="sharepoint_grounding_preview"): type: Literal[ToolType.SHAREPOINT_GROUNDING_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The object type, which is always 'sharepoint_grounding_preview'. Required. SHAREPOINT_GROUNDING_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" sharepoint_grounding_preview: "_models.SharepointGroundingToolParameters" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -9019,6 +12894,9 @@ def __init__( self, *, sharepoint_grounding_preview: "_models.SharepointGroundingToolParameters", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -9033,7 +12911,54 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolType.SHAREPOINT_GROUNDING_PREVIEW # type: ignore -class SkillObject(_Model): +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. :ivar skill_id: The unique identifier of the skill. Required. @@ -9233,7 +13158,8 @@ class StructuredInputDefinition(_Model): :vartype default_value: any :ivar schema: The JSON schema for the structured input (optional). :vartype schema: dict[str, any] - :ivar required: Whether the input property is required when the agent is invoked. + :ivar required: Whether the input property is required when the agent is invoked. Defaults to + ``false``. :vartype required: bool """ @@ -9244,7 +13170,7 @@ class StructuredInputDefinition(_Model): schema: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The JSON schema for the structured input (optional).""" required: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the input property is required when the agent is invoked.""" + """Whether the input property is required when the agent is invoked. Defaults to ``false``.""" @overload def __init__( @@ -9312,6 +13238,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. @@ -9598,6 +13573,48 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = TextResponseFormatConfigurationType.TEXT # type: ignore +class TimerRoutineTrigger(RoutineTrigger, discriminator="timer"): + """A one-shot timer routine trigger. + + :ivar type: The trigger type. Required. A one-shot timer trigger. + :vartype type: str or ~azure.ai.projects.models.TIMER + :ivar at: A future timer expression. Supported values include an ISO-8601 timestamp with an + explicit offset, a local timestamp paired with time_zone, or a positive duration from now. + Required. + :vartype at: str + :ivar time_zone: An optional IANA or Windows time zone identifier when the timer uses a local + timestamp. + :vartype time_zone: str + """ + + type: Literal[RoutineTriggerType.TIMER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The trigger type. Required. A one-shot timer trigger.""" + at: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A future timer expression. Supported values include an ISO-8601 timestamp with an explicit + offset, a local timestamp paired with time_zone, or a positive duration from now. Required.""" + time_zone: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional IANA or Windows time zone identifier when the timer uses a local timestamp.""" + + @overload + def __init__( + self, + *, + at: str, + time_zone: 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 = RoutineTriggerType.TIMER # type: ignore + + class ToolboxObject(_Model): """A toolbox that stores reusable tool definitions for agents. @@ -9666,6 +13683,57 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class ToolboxSearchPreviewTool(Tool, discriminator="toolbox_search_preview"): + """A tool for searching over the agent's toolbox. When present, deferred tools are hidden from + ``tools/list`` and only discoverable via ``search_tools`` queries at runtime. + + :ivar type: The type of the tool. Always ``toolbox_search_preview``. Required. + TOOLBOX_SEARCH_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.TOOLBOX_SEARCH_PREVIEW + :ivar name: Optional user-defined name for this tool or configuration. + :vartype name: str + :ivar description: Optional user-defined description for this tool or configuration. + :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + """ + + type: Literal[ToolType.TOOLBOX_SEARCH_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``toolbox_search_preview``. Required. TOOLBOX_SEARCH_PREVIEW.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined name for this tool or configuration.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" + + @overload + def __init__( + self, + *, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = 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.TOOLBOX_SEARCH_PREVIEW # type: ignore + + class ToolboxVersionObject(_Model): """A specific version of a toolbox. @@ -10078,6 +14146,45 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11 # type: ignore +class ToolConfig(_Model): + """Per-tool configuration that controls tool visibility and search behavior. + + :ivar pin: When true, the tool is always included in agent context and visible in + ``tools/list``. When false (default), the tool is hidden from ``tools/list`` and only + discoverable via ``tool_search``. + :vartype pin: bool + :ivar additional_search_text: Additional text indexed for tool_search. Supplements the native + tool description to improve discoverability. Does not alter ``tools/list`` output. + :vartype additional_search_text: str + """ + + pin: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """When true, the tool is always included in agent context and visible in ``tools/list``. When + false (default), the tool is hidden from ``tools/list`` and only discoverable via + ``tool_search``.""" + additional_search_text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Additional text indexed for tool_search. Supplements the native tool description to improve + discoverability. Does not alter ``tools/list`` output.""" + + @overload + def __init__( + self, + *, + pin: Optional[bool] = None, + additional_search_text: 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 ToolDescription(_Model): """Description of a tool that can be used by an agent. @@ -10140,6 +14247,266 @@ 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. 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. 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 + """ + + 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. 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: 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. 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.""" + + @overload + def __init__( + self, + *, + start_time: datetime.datetime, + description: Optional[str] = None, + agent_id: Optional[str] = None, + agent_name: Optional[str] = None, + agent_version: Optional[str] = None, + end_time: 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) + 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. 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. 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 + """ + + 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. 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: 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. 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.""" + + @overload + def __init__( + self, + *, + start_time: datetime.datetime, + description: Optional[str] = None, + agent_id: Optional[str] = None, + agent_name: Optional[str] = None, + agent_version: Optional[str] = None, + end_time: 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) + 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. @@ -10454,6 +14821,10 @@ class WebSearchTool(Tool, discriminator="web_search"): :vartype name: str :ivar description: Optional user-defined description for this tool or configuration. :vartype description: str + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] :ivar custom_search_configuration: The project connections attached to this tool. There can be a maximum of 1 connection resource attached to the tool. :vartype custom_search_configuration: ~azure.ai.projects.models.WebSearchConfiguration @@ -10478,6 +14849,12 @@ class WebSearchTool(Tool, discriminator="web_search"): """Optional user-defined name for this tool or configuration.""" description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Optional user-defined description for this tool or configuration.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" custom_search_configuration: Optional["_models.WebSearchConfiguration"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -10493,6 +14870,7 @@ def __init__( search_context_size: Optional[Literal["low", "medium", "high"]] = None, name: Optional[str] = None, description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, custom_search_configuration: Optional["_models.WebSearchConfiguration"] = None, ) -> None: ... @@ -10611,32 +14989,41 @@ class WorkIQPreviewTool(Tool, discriminator="work_iq_preview"): :ivar type: The object type, which is always 'work_iq_preview'. Required. WORK_IQ_PREVIEW. :vartype type: str or ~azure.ai.projects.models.WORK_IQ_PREVIEW + :ivar project_connection_id: The ID of the WorkIQ project connection. Required. + :vartype project_connection_id: str :ivar name: Optional user-defined name for this tool or configuration. :vartype name: str :ivar description: Optional user-defined description for this tool or configuration. :vartype description: str - :ivar work_iq_preview: The WorkIQ tool parameters. Required. - :vartype work_iq_preview: ~azure.ai.projects.models.WorkIQPreviewToolParameters + :ivar tool_configs: Per-tool configuration map. Keys are tool names or ``*`` (catch-all + default). Resolution order: exact tool name match takes priority over ``*``. Unknown tool names + are silently ignored at runtime. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] """ type: Literal[ToolType.WORK_IQ_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The object type, which is always 'work_iq_preview'. Required. WORK_IQ_PREVIEW.""" + project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the WorkIQ project connection. Required.""" name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Optional user-defined name for this tool or configuration.""" description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Optional user-defined description for this tool or configuration.""" - work_iq_preview: "_models.WorkIQPreviewToolParameters" = rest_field( + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The WorkIQ tool parameters. Required.""" + """Per-tool configuration map. Keys are tool names or ``*`` (catch-all default). Resolution order: + exact tool name match takes priority over ``*``. Unknown tool names are silently ignored at + runtime.""" @overload def __init__( self, *, - work_iq_preview: "_models.WorkIQPreviewToolParameters", + project_connection_id: str, name: Optional[str] = None, description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -10649,31 +15036,3 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.type = ToolType.WORK_IQ_PREVIEW # type: ignore - - -class WorkIQPreviewToolParameters(_Model): - """The WorkIQ tool parameters. - - :ivar project_connection_id: The ID of the WorkIQ project connection. Required. - :vartype project_connection_id: str - """ - - project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the WorkIQ project connection. Required.""" - - @overload - def __init__( - self, - *, - project_connection_id: 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) 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 a8b53026f7f3..12dba1e0a0e2 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 @@ -39,21 +39,36 @@ _FOUNDRY_FEATURES_HEADER_NAME: Final[str] = "Foundry-Features" """The HTTP header name used to opt in to Foundry preview features.""" +_PREVIEW_FEATURE_REQUIRED_CODE: Final = "preview_feature_required" +_PREVIEW_FEATURE_ADDED_ERROR_MESSAGE: Final = ( + '\n**Python SDK users**: This operation requires you to set "allow_preview=True" ' + "when calling the AIProjectClient constructor. " + "\nNote that preview features are under development and subject to change. They should not be used in production environments." +) +_AGENT_OPERATION_FEATURE_HEADERS: Final[str] = ",".join( + [ + _AgentDefinitionOptInKeys.HOSTED_AGENTS_V1_PREVIEW.value, + _AgentDefinitionOptInKeys.WORKFLOW_AGENTS_V1_PREVIEW.value, + _AgentDefinitionOptInKeys.AGENT_ENDPOINT_V1_PREVIEW.value, + _AgentDefinitionOptInKeys.CODE_AGENTS_V1_PREVIEW.value, + _AgentDefinitionOptInKeys.EXTERNAL_AGENTS_V1_PREVIEW.value, + _FoundryFeaturesOptInKeys.AGENTS_OPTIMIZATION_V1_PREVIEW.value, + ] +) + _BETA_OPERATION_FEATURE_HEADERS: Final[dict] = { "evaluation_taxonomies": _FoundryFeaturesOptInKeys.EVALUATIONS_V1_PREVIEW.value, "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, + "routines": _FoundryFeaturesOptInKeys.ROUTINES_V1_PREVIEW.value, "schedules": _FoundryFeaturesOptInKeys.SCHEDULES_V1_PREVIEW.value, - "toolboxes": _FoundryFeaturesOptInKeys.TOOLBOXES_V1_PREVIEW.value, + "toolboxes": "Toolboxes=V1Preview", "skills": _FoundryFeaturesOptInKeys.SKILLS_V1_PREVIEW.value, - "agents": ",".join( - [ - _AgentDefinitionOptInKeys.HOSTED_AGENTS_V1_PREVIEW.value, - _AgentDefinitionOptInKeys.AGENT_ENDPOINT_V1_PREVIEW.value, - ] - ), + "datasets": _FoundryFeaturesOptInKeys.DATA_GENERATION_JOBS_V1_PREVIEW.value, + "agents": _AGENT_OPERATION_FEATURE_HEADERS, } """Foundry-Features header values keyed by beta sub-client property name.""" 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 52f7a21b1821..3ecdf36cc95b 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 @@ -35,8 +35,9 @@ from .. import models as _models from .._configuration import AIProjectClientConfiguration -from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from .._utils.model_base import Model as _Model, SdkJSONEncoder, _deserialize, _failsafe_deserialize from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import prepare_multipart_form_data JSON = MutableMapping[str, Any] _Unset: Any = object() @@ -72,7 +73,7 @@ def build_agents_get_request(agent_name: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_agents_delete_request(agent_name: str, **kwargs: Any) -> HttpRequest: +def build_agents_delete_request(agent_name: str, *, force: Optional[bool] = None, **kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -88,6 +89,8 @@ def build_agents_delete_request(agent_name: str, **kwargs: Any) -> HttpRequest: _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + if force is not None: + _params["force"] = _SERIALIZER.query("force", force, "bool") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers @@ -214,7 +217,9 @@ def build_agents_get_version_request(agent_name: str, agent_version: str, **kwar return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_agents_delete_version_request(agent_name: str, agent_version: str, **kwargs: Any) -> HttpRequest: +def build_agents_delete_version_request( + agent_name: str, agent_version: str, *, force: Optional[bool] = None, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -231,6 +236,8 @@ def build_agents_delete_version_request(agent_name: str, agent_version: str, **k _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + if force is not None: + _params["force"] = _SERIALIZER.query("force", force, "bool") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers @@ -826,7 +833,64 @@ def build_beta_agents_patch_agent_details_request( # pylint: disable=name-too-l return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_agents_create_session_request(agent_name: str, *, isolation_key: str, **kwargs: Any) -> HttpRequest: +def build_beta_agents_create_version_from_code_request( # pylint: disable=name-too-long + agent_name: str, *, code_zip_sha256: 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 = "/agents/{agent_name}/versions" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_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["x-ms-code-zip-sha256"] = _SERIALIZER.header("code_zip_sha256", code_zip_sha256, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_agents_download_code_request( + agent_name: str, *, agent_version: 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/zip") + + # Construct URL + _url = "/agents/{agent_name}/code:download" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if agent_version is not None: + _params["agent_version"] = _SERIALIZER.query("agent_version", agent_version, "str") + _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_agents_create_session_request( + agent_name: str, *, user_isolation_key: Optional[str] = None, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -846,7 +910,8 @@ def build_beta_agents_create_session_request(agent_name: str, *, isolation_key: _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers - _headers["x-session-isolation-key"] = _SERIALIZER.header("isolation_key", isolation_key, "str") + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -854,7 +919,9 @@ def build_beta_agents_create_session_request(agent_name: str, *, isolation_key: return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_agents_get_session_request(agent_name: str, session_id: str, **kwargs: Any) -> HttpRequest: +def build_beta_agents_get_session_request( + agent_name: str, session_id: str, *, user_isolation_key: Optional[str] = None, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -874,13 +941,15 @@ def build_beta_agents_get_session_request(agent_name: str, session_id: str, **kw _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) def build_beta_agents_delete_session_request( - agent_name: str, session_id: str, *, isolation_key: str, **kwargs: Any + agent_name: str, session_id: str, *, user_isolation_key: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -899,7 +968,8 @@ def build_beta_agents_delete_session_request( _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers - _headers["x-session-isolation-key"] = _SERIALIZER.header("isolation_key", isolation_key, "str") + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) @@ -907,6 +977,7 @@ def build_beta_agents_delete_session_request( def build_beta_agents_list_sessions_request( agent_name: str, *, + user_isolation_key: Optional[str] = None, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, after: Optional[str] = None, @@ -939,6 +1010,8 @@ def build_beta_agents_list_sessions_request( _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) @@ -973,7 +1046,7 @@ def build_beta_agents_get_session_log_stream_request( # pylint: disable=name-to def build_beta_agents_upload_session_file_request( # pylint: disable=name-too-long - agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + agent_name: str, agent_session_id: str, *, path: str, user_isolation_key: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -997,13 +1070,15 @@ def build_beta_agents_upload_session_file_request( # pylint: disable=name-too-l # Construct headers _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) def build_beta_agents_download_session_file_request( # pylint: disable=name-too-long - agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + agent_name: str, agent_session_id: str, *, path: str, user_isolation_key: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1025,13 +1100,15 @@ def build_beta_agents_download_session_file_request( # pylint: disable=name-too _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) def build_beta_agents_get_session_files_request( # pylint: disable=name-too-long - agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + agent_name: str, agent_session_id: str, *, path: str, user_isolation_key: Optional[str] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1053,14 +1130,23 @@ def build_beta_agents_get_session_files_request( # pylint: disable=name-too-lon _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) def build_beta_agents_delete_session_file_request( # pylint: disable=name-too-long - agent_name: str, agent_session_id: str, *, path: str, recursive: Optional[bool] = None, **kwargs: Any + agent_name: str, + agent_session_id: str, + *, + path: str, + recursive: Optional[bool] = None, + user_isolation_key: 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")) @@ -1079,22 +1165,52 @@ def build_beta_agents_delete_session_file_request( # pylint: disable=name-too-l _params["recursive"] = _SERIALIZER.query("recursive", recursive, "bool") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + # Construct headers + if user_isolation_key is not None: + _headers["x-ms-user-isolation-key"] = _SERIALIZER.header("user_isolation_key", user_isolation_key, "str") + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluation_taxonomies_get_request( # pylint: disable=name-too-long - name: str, **kwargs: Any + +def build_beta_agents_create_optimization_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 = "/evaluationtaxonomies/{name}" + _url = "/agent_optimization_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_agents_get_optimization_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 = "/agent_optimization_jobs/{jobId}" path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), + "jobId": _SERIALIZER.url("job_id", job_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1108,8 +1224,15 @@ def build_beta_evaluation_taxonomies_get_request( # pylint: disable=name-too-lo return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluation_taxonomies_list_request( # pylint: disable=name-too-long - *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any +def build_beta_agents_list_optimization_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, + status: Optional[Union[str, _models.JobStatus]] = None, + agent_name: Optional[str] = None, + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1118,14 +1241,22 @@ def build_beta_evaluation_taxonomies_list_request( # pylint: disable=name-too-l accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluationtaxonomies" + _url = "/agent_optimization_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 status is not None: + _params["status"] = _SERIALIZER.query("status", status, "str") + if agent_name is not None: + _params["agent_name"] = _SERIALIZER.query("agent_name", agent_name, "str") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - if input_name is not None: - _params["inputName"] = _SERIALIZER.query("input_name", input_name, "str") - if input_type is not None: - _params["inputType"] = _SERIALIZER.query("input_type", input_type, "str") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1133,16 +1264,42 @@ def build_beta_evaluation_taxonomies_list_request( # pylint: disable=name-too-l return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluation_taxonomies_delete_request( # pylint: disable=name-too-long - name: str, **kwargs: Any +def build_beta_agents_cancel_optimization_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 = "/evaluationtaxonomies/{name}" + _url = "/agent_optimization_jobs/{jobId}:cancel" path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), + "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_agents_delete_optimization_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 = "/agent_optimization_jobs/{jobId}" + path_format_arguments = { + "jobId": _SERIALIZER.url("job_id", job_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1153,49 +1310,60 @@ def build_beta_evaluation_taxonomies_delete_request( # pylint: disable=name-too return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) -def build_beta_evaluation_taxonomies_create_request( # pylint: disable=name-too-long - name: str, **kwargs: Any +def build_beta_agents_list_optimization_candidates_request( # pylint: disable=name-too-long + job_id: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/evaluationtaxonomies/{name}" + _url = "/agent_optimization_jobs/{jobId}/candidates" path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), + "jobId": _SERIALIZER.url("job_id", job_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore # 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") _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="PUT", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluation_taxonomies_update_request( # pylint: disable=name-too-long - name: str, **kwargs: Any +def build_beta_agents_get_optimization_candidate_request( # pylint: disable=name-too-long + job_id: str, candidate_id: 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 = "/evaluationtaxonomies/{name}" + _url = "/agent_optimization_jobs/{jobId}/candidates/{candidateId}" path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), + "jobId": _SERIALIZER.url("job_id", job_id, "str"), + "candidateId": _SERIALIZER.url("candidate_id", candidate_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1204,19 +1372,13 @@ def build_beta_evaluation_taxonomies_update_request( # pylint: disable=name-too _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) + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_list_versions_request( # pylint: disable=name-too-long - name: str, - *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, - **kwargs: Any +def build_beta_agents_get_optimization_candidate_config_request( # pylint: disable=name-too-long + job_id: str, candidate_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1225,19 +1387,16 @@ def build_beta_evaluators_list_versions_request( # pylint: disable=name-too-lon accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluators/{name}/versions" + _url = "/agent_optimization_jobs/{jobId}/candidates/{candidateId}/config" path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), + "jobId": _SERIALIZER.url("job_id", job_id, "str"), + "candidateId": _SERIALIZER.url("candidate_id", candidate_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - if type is not None: - _params["type"] = _SERIALIZER.query("type", type, "str") - if limit is not None: - _params["limit"] = _SERIALIZER.query("limit", limit, "int") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1245,11 +1404,8 @@ def build_beta_evaluators_list_versions_request( # pylint: disable=name-too-lon return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_list_request( - *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, - **kwargs: Any +def build_beta_agents_get_optimization_candidate_results_request( # pylint: disable=name-too-long + job_id: str, candidate_id: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1258,14 +1414,16 @@ def build_beta_evaluators_list_request( accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluators" + _url = "/agent_optimization_jobs/{jobId}/candidates/{candidateId}/results" + path_format_arguments = { + "jobId": _SERIALIZER.url("job_id", job_id, "str"), + "candidateId": _SERIALIZER.url("candidate_id", candidate_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - if type is not None: - _params["type"] = _SERIALIZER.query("type", type, "str") - if limit is not None: - _params["limit"] = _SERIALIZER.query("limit", limit, "int") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1273,8 +1431,8 @@ def build_beta_evaluators_list_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_get_version_request( # pylint: disable=name-too-long - name: str, version: str, **kwargs: Any +def build_beta_evaluation_taxonomies_get_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 {}) @@ -1283,10 +1441,9 @@ def build_beta_evaluators_get_version_request( # pylint: disable=name-too-long accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluators/{name}/versions/{version}" + _url = "/evaluationtaxonomies/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), - "version": _SERIALIZER.url("version", version, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1300,17 +1457,41 @@ def build_beta_evaluators_get_version_request( # pylint: disable=name-too-long return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_delete_version_request( # pylint: disable=name-too-long - name: str, version: str, **kwargs: Any +def build_beta_evaluation_taxonomies_list_request( # pylint: disable=name-too-long + *, input_name: Optional[str] = None, input_type: 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 = "/evaluators/{name}/versions/{version}" + _url = "/evaluationtaxonomies" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + if input_name is not None: + _params["inputName"] = _SERIALIZER.query("input_name", input_name, "str") + if input_type is not None: + _params["inputType"] = _SERIALIZER.query("input_type", input_type, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_evaluation_taxonomies_delete_request( # pylint: disable=name-too-long + name: 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 = "/evaluationtaxonomies/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), - "version": _SERIALIZER.url("version", version, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1321,7 +1502,7 @@ def build_beta_evaluators_delete_version_request( # pylint: disable=name-too-lo return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) -def build_beta_evaluators_create_version_request( # pylint: disable=name-too-long +def build_beta_evaluation_taxonomies_create_request( # pylint: disable=name-too-long name: str, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) @@ -1332,7 +1513,7 @@ def build_beta_evaluators_create_version_request( # pylint: disable=name-too-lo accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluators/{name}/versions" + _url = "/evaluationtaxonomies/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -1347,11 +1528,11 @@ def build_beta_evaluators_create_version_request( # pylint: disable=name-too-lo _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) + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_update_version_request( # pylint: disable=name-too-long - name: str, version: str, **kwargs: Any +def build_beta_evaluation_taxonomies_update_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 {}) @@ -1361,10 +1542,9 @@ def build_beta_evaluators_update_version_request( # pylint: disable=name-too-lo accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluators/{name}/versions/{version}" + _url = "/evaluationtaxonomies/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), - "version": _SERIALIZER.url("version", version, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1380,55 +1560,33 @@ 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_insights_generate_request(**kwargs: Any) -> HttpRequest: +def build_beta_evaluators_list_versions_request( # pylint: disable=name-too-long + name: str, + *, + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, + limit: Optional[int] = 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 = "/insights" - - # 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 = "/evaluators/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "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") + if type is not None: + _params["type"] = _SERIALIZER.query("type", type, "str") + if limit is not None: + _params["limit"] = _SERIALIZER.query("limit", limit, "int") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1436,13 +1594,10 @@ def build_beta_insights_get_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_insights_list_request( +def build_beta_evaluators_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, + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, + limit: Optional[int] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) @@ -1452,20 +1607,14 @@ def build_beta_insights_list_request( accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/insights" + _url = "/evaluators" # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "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") + if limit is not None: + _params["limit"] = _SERIALIZER.query("limit", limit, "int") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1473,40 +1622,20 @@ def build_beta_insights_list_request( 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: +def build_beta_evaluators_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 {}) - 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}" + _url = "/evaluators/{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 @@ -1515,24 +1644,22 @@ def build_beta_memory_stores_update_request(name: str, **kwargs: Any) -> HttpReq _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) + return HttpRequest(method="GET", 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 {}) +def build_beta_evaluators_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")) - accept = _headers.pop("Accept", "application/json") - # Construct URL - _url = "/memory_stores/{name}" + _url = "/evaluators/{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 @@ -1540,57 +1667,53 @@ def build_beta_memory_stores_get_request(name: str, **kwargs: Any) -> HttpReques # 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="DELETE", url=_url, params=_params, **kwargs) -def build_beta_memory_stores_list_request( - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - after: Optional[str] = None, - before: Optional[str] = None, - **kwargs: Any +def build_beta_evaluators_create_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 = "/memory_stores" + _url = "/evaluators/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore # 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") _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="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_memory_stores_delete_request(name: str, **kwargs: Any) -> HttpRequest: +def build_beta_evaluators_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 = "/memory_stores/{name}" + _url = "/evaluators/{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 @@ -1599,13 +1722,15 @@ def build_beta_memory_stores_delete_request(name: str, **kwargs: Any) -> HttpReq _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="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_memory_stores_search_memories_request( # pylint: disable=name-too-long - name: str, **kwargs: Any +def build_beta_evaluators_pending_upload_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 {}) @@ -1615,9 +1740,10 @@ def build_beta_memory_stores_search_memories_request( # pylint: disable=name-to accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/memory_stores/{name}:search_memories" + _url = "/evaluators/{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 @@ -1633,8 +1759,8 @@ def build_beta_memory_stores_search_memories_request( # pylint: disable=name-to return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_memory_stores_update_memories_request( # pylint: disable=name-too-long - name: str, **kwargs: Any +def build_beta_evaluators_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 {}) @@ -1644,9 +1770,10 @@ def build_beta_memory_stores_update_memories_request( # pylint: disable=name-to accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/memory_stores/{name}:update_memories" + _url = "/evaluators/{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 @@ -1662,8 +1789,8 @@ def build_beta_memory_stores_update_memories_request( # pylint: disable=name-to return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_memory_stores_delete_scope_request( # pylint: disable=name-too-long - name: str, **kwargs: Any +def build_beta_evaluators_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 {}) @@ -1673,17 +1800,14 @@ def build_beta_memory_stores_delete_scope_request( # pylint: disable=name-too-l accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/memory_stores/{name}:delete_scope" - path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore + _url = "/evaluator_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") @@ -1691,7 +1815,9 @@ 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_red_teams_get_request(name: str, **kwargs: Any) -> HttpRequest: +def build_beta_evaluators_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 {}) @@ -1699,9 +1825,9 @@ def build_beta_red_teams_get_request(name: str, **kwargs: Any) -> HttpRequest: accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/redTeams/runs/{name}" + _url = "/evaluator_generation_jobs/{jobId}" path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), + "jobId": _SERIALIZER.url("job_id", job_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1715,7 +1841,14 @@ def build_beta_red_teams_get_request(name: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_red_teams_list_request(**kwargs: Any) -> HttpRequest: +def build_beta_evaluators_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, + **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1723,9 +1856,17 @@ def build_beta_red_teams_list_request(**kwargs: Any) -> HttpRequest: accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/redTeams/runs" + _url = "/evaluator_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") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers @@ -1734,36 +1875,42 @@ def build_beta_red_teams_list_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_red_teams_create_request(**kwargs: Any) -> HttpRequest: +def build_beta_evaluators_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 {}) - 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 = "/redTeams/runs:run" + _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 # 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_schedules_delete_request(schedule_id: str, **kwargs: Any) -> HttpRequest: +def build_beta_evaluators_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 = "/schedules/{id}" + _url = "/evaluator_generation_jobs/{jobId}" path_format_arguments = { - "id": _SERIALIZER.url("schedule_id", schedule_id, "str"), + "jobId": _SERIALIZER.url("job_id", job_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1774,32 +1921,36 @@ def build_beta_schedules_delete_request(schedule_id: str, **kwargs: Any) -> Http return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) -def build_beta_schedules_get_request(schedule_id: str, **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 {}) + 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 = "/schedules/{id}" - path_format_arguments = { - "id": _SERIALIZER.url("schedule_id", schedule_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore + _url = "/insights" # 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="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_schedules_list_request( - *, type: Optional[Union[str, _models.ScheduleTaskType]] = None, enabled: Optional[bool] = None, **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 {}) @@ -1808,14 +1959,17 @@ def build_beta_schedules_list_request( accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/schedules" + _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") - if type is not None: - _params["type"] = _SERIALIZER.query("type", type, "str") - if enabled is not None: - _params["enabled"] = _SERIALIZER.query("enabled", enabled, "bool") # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1823,52 +1977,35 @@ def build_beta_schedules_list_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_schedules_create_or_update_request( # pylint: disable=name-too-long - schedule_id: str, **kwargs: Any +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 {}) - 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 = "/schedules/{id}" - path_format_arguments = { - "id": _SERIALIZER.url("schedule_id", schedule_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 - 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="PUT", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_schedules_get_run_request(schedule_id: str, run_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 = "/schedules/{schedule_id}/runs/{run_id}" - path_format_arguments = { - "schedule_id": _SERIALIZER.url("schedule_id", schedule_id, "str"), - "run_id": _SERIALIZER.url("run_id", run_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore + _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 @@ -1877,43 +2014,29 @@ def build_beta_schedules_get_run_request(schedule_id: str, run_id: str, **kwargs return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_schedules_list_runs_request( - schedule_id: str, - *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, - **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 = "/schedules/{id}/runs" - path_format_arguments = { - "id": _SERIALIZER.url("schedule_id", schedule_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") - if type is not None: - _params["type"] = _SERIALIZER.query("type", type, "str") - if enabled is not None: - _params["enabled"] = _SERIALIZER.query("enabled", enabled, "bool") # 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="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_create_version_request( # pylint: disable=name-too-long - name: 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 {}) @@ -1922,7 +2045,7 @@ def build_beta_toolboxes_create_version_request( # pylint: disable=name-too-lon accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/toolboxes/{name}/versions" + _url = "/memory_stores/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -1940,7 +2063,7 @@ def build_beta_toolboxes_create_version_request( # pylint: disable=name-too-lon return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_get_request(name: str, **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 {}) @@ -1948,7 +2071,7 @@ def build_beta_toolboxes_get_request(name: str, **kwargs: Any) -> HttpRequest: accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/toolboxes/{name}" + _url = "/memory_stores/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -1964,7 +2087,7 @@ def build_beta_toolboxes_get_request(name: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_list_request( +def build_beta_memory_stores_list_request( *, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, @@ -1979,7 +2102,7 @@ def build_beta_toolboxes_list_request( accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/toolboxes" + _url = "/memory_stores" # Construct parameters if limit is not None: @@ -1998,15 +2121,7 @@ def build_beta_toolboxes_list_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_list_versions_request( # pylint: disable=name-too-long - name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - after: Optional[str] = None, - before: Optional[str] = None, - **kwargs: Any -) -> HttpRequest: +def build_beta_memory_stores_delete_request(name: str, **kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -2014,7 +2129,7 @@ def build_beta_toolboxes_list_versions_request( # pylint: disable=name-too-long accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/toolboxes/{name}/versions" + _url = "/memory_stores/{name}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -2022,34 +2137,28 @@ def build_beta_toolboxes_list_versions_request( # pylint: disable=name-too-long _url: str = _url.format(**path_format_arguments) # type: ignore # 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") _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="DELETE", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_get_version_request(name: str, version: str, **kwargs: Any) -> HttpRequest: +def build_beta_memory_stores_search_memories_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 = "/toolboxes/{name}/versions/{version}" + _url = "/memory_stores/{name}:search_memories" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), - "version": _SERIALIZER.url("version", version, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -2058,12 +2167,16 @@ def build_beta_toolboxes_get_version_request(name: str, version: str, **kwargs: _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="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_update_request(name: str, **kwargs: Any) -> HttpRequest: +def build_beta_memory_stores_update_memories_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 {}) @@ -2072,7 +2185,7 @@ def build_beta_toolboxes_update_request(name: str, **kwargs: Any) -> HttpRequest accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/toolboxes/{name}" + _url = "/memory_stores/{name}:update_memories" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -2087,15 +2200,21 @@ def build_beta_toolboxes_update_request(name: str, **kwargs: Any) -> HttpRequest _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) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_toolboxes_delete_request(name: str, **kwargs: Any) -> HttpRequest: +def build_beta_memory_stores_delete_scope_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 = "/toolboxes/{name}" + _url = "/memory_stores/{name}:delete_scope" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -2105,20 +2224,28 @@ def build_beta_toolboxes_delete_request(name: str, **kwargs: Any) -> HttpRequest # 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_toolboxes_delete_version_request( # pylint: disable=name-too-long - name: str, version: str, **kwargs: Any +def build_beta_memory_stores_create_memory_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 = "/toolboxes/{name}/versions/{version}" + _url = "/memory_stores/{name}/items" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), - "version": _SERIALIZER.url("version", version, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -2126,10 +2253,17 @@ def build_beta_toolboxes_delete_version_request( # pylint: disable=name-too-lon # 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_skills_create_request(**kwargs: Any) -> HttpRequest: +def build_beta_memory_stores_update_memory_request( # pylint: disable=name-too-long + name: str, memory_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -2138,7 +2272,13 @@ def build_beta_skills_create_request(**kwargs: Any) -> HttpRequest: accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/skills" + _url = "/memory_stores/{name}/items/{memory_id}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "memory_id": _SERIALIZER.url("memory_id", memory_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") @@ -2151,36 +2291,52 @@ def build_beta_skills_create_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_skills_create_from_package_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long +def build_beta_memory_stores_get_memory_request( # pylint: disable=name-too-long + name: str, memory_id: str, **kwargs: Any +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type: str = kwargs.pop("content_type") api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/skills:import" + _url = "/memory_stores/{name}/items/{memory_id}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "memory_id": _SERIALIZER.url("memory_id", memory_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["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) + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_skills_get_request(name: str, **kwargs: Any) -> HttpRequest: +def build_beta_memory_stores_list_memories_request( # pylint: disable=name-too-long + name: str, + *, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/skills/{name}" + _url = "/memory_stores/{name}/items:list" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), } @@ -2188,25 +2344,40 @@ def build_beta_skills_get_request(name: str, **kwargs: Any) -> HttpRequest: _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + if kind is not None: + _params["kind"] = _SERIALIZER.query("kind", kind, "str") + 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") _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="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_skills_download_request(name: str, **kwargs: Any) -> HttpRequest: +def build_beta_memory_stores_delete_memory_request( # pylint: disable=name-too-long + name: str, memory_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/zip") + accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/skills/{name}:download" + _url = "/memory_stores/{name}/items/{memory_id}" path_format_arguments = { "name": _SERIALIZER.url("name", name, "str"), + "memory_id": _SERIALIZER.url("memory_id", memory_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -2217,17 +2388,10 @@ def build_beta_skills_download_request(name: str, **kwargs: Any) -> HttpRequest: # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_skills_list_request( - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - after: Optional[str] = None, - before: Optional[str] = None, - **kwargs: Any -) -> HttpRequest: +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 {}) @@ -2235,17 +2399,14 @@ def build_beta_skills_list_request( accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/skills" + _url = "/models/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore # 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") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers @@ -2254,34 +2415,26 @@ def build_beta_skills_list_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_skills_update_request(name: str, **kwargs: Any) -> HttpRequest: +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 {}) - 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 = "/skills/{name}" - path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore + _url = "/models" # 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) + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_skills_delete_request(name: str, **kwargs: Any) -> HttpRequest: +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 {}) @@ -2289,9 +2442,10 @@ def build_beta_skills_delete_request(name: str, **kwargs: Any) -> HttpRequest: accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/skills/{name}" + _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 @@ -2302,233 +2456,1353 @@ def build_beta_skills_delete_request(name: str, **kwargs: Any) -> HttpRequest: # Construct headers _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) - + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class BetaOperations: # pylint: disable=too-many-instance-attributes - """ - .. warning:: - **DO NOT** instantiate this class directly. - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`beta` attribute. - """ +def build_beta_models_delete_request(name: str, version: str, **kwargs: Any) -> HttpRequest: + _params = case_insensitive_dict(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") + 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"), + } - self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) - self.evaluation_taxonomies = BetaEvaluationTaxonomiesOperations( - self._client, self._config, self._serialize, self._deserialize - ) - 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.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) - self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) + _url: str = _url.format(**path_format_arguments) # type: ignore + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") -class AgentsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) - 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") +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 {}) - @distributed_trace - def get(self, agent_name: str, **kwargs: Any) -> _models.AgentDetails: - """Retrieves the agent. + 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") - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + # Construct URL + _url = "/models/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + _url: str = _url.format(**path_format_arguments) # type: ignore - cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - _request = build_agents_get_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) + # 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") - _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 HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **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) +def build_beta_models_pending_create_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 {}) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.AgentDetails, response.json()) + 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") - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + # Construct URL + _url = "/models/{name}/versions/{version}/createAsync" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } - return deserialized # type: ignore + _url: str = _url.format(**path_format_arguments) # type: ignore - @distributed_trace - def delete(self, agent_name: str, **kwargs: Any) -> _models.DeleteAgentResponse: - """Deletes an agent. + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - :param agent_name: The name of the agent to delete. Required. - :type agent_name: str - :return: DeleteAgentResponse. The DeleteAgentResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteAgentResponse - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + # 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") - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - cls: ClsType[_models.DeleteAgentResponse] = kwargs.pop("cls", None) - _request = build_agents_delete_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) +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 {}) - _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 - ) + 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") - response = pipeline_response.http_response + # Construct URL + _url = "/models/{name}/versions/{version}/startPendingUpload" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } - 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) + _url: str = _url.format(**path_format_arguments) # type: ignore - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DeleteAgentResponse, response.json()) + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + # 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 deserialized # type: ignore + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - @distributed_trace - def list( - self, - *, - kind: Optional[Union[str, _models.AgentKind]] = None, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.AgentDetails"]: - """Returns the list of all agents. - :keyword kind: Filter agents by kind. If not provided, all agents are returned. Known values - are: "prompt", "hosted", and "workflow". Default value is None. - :paramtype kind: str or ~azure.ai.projects.models.AgentKind - :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 AgentDetails - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.AgentDetails] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} +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 {}) - cls: ClsType[List[_models.AgentDetails]] = kwargs.pop("cls", None) + 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") - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + # Construct URL + _url = "/models/{name}/versions/{version}/credentials" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } - def prepare_request(_continuation_token=None): + _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 {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/redTeams/runs/{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) + + +def build_beta_red_teams_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 = "/redTeams/runs" + + # 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_red_teams_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 = "/redTeams/runs:run" + + # 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_routines_create_or_update_request( # pylint: disable=name-too-long + routine_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 = "/routines/{routine_name}" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_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="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_routines_get_request(routine_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 = "/routines/{routine_name}" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_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_routines_enable_request(routine_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 = "/routines/{routine_name}:enable" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_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="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_routines_disable_request(routine_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 = "/routines/{routine_name}:disable" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_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="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_routines_list_request( + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/routines" + + # 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") + _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_routines_delete_request(routine_name: 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 = "/routines/{routine_name}" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_name, "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_routines_list_runs_request( + routine_name: str, + *, + filter: Optional[str] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/routines/{routine_name}/runs" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if filter is not None: + _params["filter"] = _SERIALIZER.query("filter", filter, "str") + 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") + _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_routines_dispatch_request(routine_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 = "/routines/{routine_name}:dispatch_async" + path_format_arguments = { + "routine_name": _SERIALIZER.url("routine_name", routine_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_schedules_delete_request(schedule_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 = "/schedules/{id}" + path_format_arguments = { + "id": _SERIALIZER.url("schedule_id", schedule_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) + + +def build_beta_schedules_get_request(schedule_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 = "/schedules/{id}" + path_format_arguments = { + "id": _SERIALIZER.url("schedule_id", schedule_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_schedules_list_request( + *, type: Optional[Union[str, _models.ScheduleTaskType]] = None, enabled: 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 = "/schedules" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + if type is not None: + _params["type"] = _SERIALIZER.query("type", type, "str") + if enabled is not None: + _params["enabled"] = _SERIALIZER.query("enabled", enabled, "bool") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_schedules_create_or_update_request( # pylint: disable=name-too-long + schedule_id: 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 = "/schedules/{id}" + path_format_arguments = { + "id": _SERIALIZER.url("schedule_id", schedule_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 + 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="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_schedules_get_run_request(schedule_id: str, run_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 = "/schedules/{schedule_id}/runs/{run_id}" + path_format_arguments = { + "schedule_id": _SERIALIZER.url("schedule_id", schedule_id, "str"), + "run_id": _SERIALIZER.url("run_id", run_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_schedules_list_runs_request( + schedule_id: str, + *, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: 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 = "/schedules/{id}/runs" + path_format_arguments = { + "id": _SERIALIZER.url("schedule_id", schedule_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + if type is not None: + _params["type"] = _SERIALIZER.query("type", type, "str") + if enabled is not None: + _params["enabled"] = _SERIALIZER.query("enabled", enabled, "bool") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_toolboxes_create_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 = "/toolboxes/{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_beta_toolboxes_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 = "/toolboxes/{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) + + +def build_beta_toolboxes_list_request( + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/toolboxes" + + # 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") + _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_toolboxes_list_versions_request( # pylint: disable=name-too-long + name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/toolboxes/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # 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") + _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_toolboxes_get_version_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 = "/toolboxes/{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_toolboxes_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 = "/toolboxes/{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="PATCH", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_toolboxes_delete_request(name: 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 = "/toolboxes/{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") + + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + + +def build_beta_toolboxes_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 = "/toolboxes/{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_skills_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 = "/skills" + + # 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_skills_create_from_package_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: str = kwargs.pop("content_type") + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/skills:import" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _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_skills_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 = "/skills/{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) + + +def build_beta_skills_download_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/zip") + + # Construct URL + _url = "/skills/{name}:download" + 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_skills_list_request( + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: 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 = "/skills" + + # 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") + _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_skills_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 = "/skills/{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_skills_delete_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 = "/skills/{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="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:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`beta` 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") + + self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) + self.evaluation_taxonomies = BetaEvaluationTaxonomiesOperations( + self._client, self._config, self._serialize, self._deserialize + ) + 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.routines = BetaRoutinesOperations(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) + self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) + self.datasets = BetaDatasetsOperations(self._client, self._config, self._serialize, self._deserialize) + + +class AgentsOperations: + """ + .. 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") + + @distributed_trace + def get(self, agent_name: str, **kwargs: Any) -> _models.AgentDetails: + """Retrieves the agent. + + :param agent_name: The name of the agent to retrieve. Required. + :type agent_name: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :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.AgentDetails] = kwargs.pop("cls", None) + + _request = build_agents_get_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) + + _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.AgentDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete(self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any) -> _models.DeleteAgentResponse: + """Deletes an agent. For hosted agents, if any version has active sessions, the request is + rejected with HTTP 409 unless ``force`` is set to true. When force is true, all associated + sessions are cascade-deleted along with the agent and its versions. + + :param agent_name: The name of the agent to delete. Required. + :type agent_name: str + :keyword force: For Hosted Agents, if true, force-deletes the agent even if its versions have + active sessions, cascading deletion to all associated sessions. Defaults to ``false``. This + value is not relevant for other Agent types. Default value is None. + :paramtype force: bool + :return: DeleteAgentResponse. The DeleteAgentResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteAgentResponse + :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.DeleteAgentResponse] = kwargs.pop("cls", None) + + _request = build_agents_delete_request( + agent_name=agent_name, + force=force, + 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.DeleteAgentResponse, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + kind: Optional[Union[str, _models.AgentKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.AgentDetails"]: + """Returns the list of all agents. + + :keyword kind: Filter agents by kind. If not provided, all agents are returned. Known values + are: "prompt", "hosted", "workflow", and "external". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.AgentKind + :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 AgentDetails + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.AgentDetails] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.AgentDetails]] = 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_agents_list_request( kind=kind, @@ -2540,56 +3814,2823 @@ def prepare_request(_continuation_token=None): 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) + 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.AgentDetails], + 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_version( + self, + agent_name: str, + *, + definition: _models.AgentDefinition, + content_type: str = "application/json", + metadata: Optional[dict[str, str]] = None, + description: Optional[str] = None, + blueprint_reference: Optional[_models.AgentBlueprintReference] = None, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version. + + :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 + :keyword definition: The agent definition. This can be a workflow, hosted agent, or a simple + agent definition. Required. + :paramtype definition: ~azure.ai.projects.models.AgentDefinition + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: 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] + :keyword description: A human-readable description of the agent. Default value is None. + :paramtype description: str + :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. + :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_version( + self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version. + + :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 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: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_version( + self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version. + + :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 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: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_version( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + definition: _models.AgentDefinition = _Unset, + metadata: Optional[dict[str, str]] = None, + description: Optional[str] = None, + blueprint_reference: Optional[_models.AgentBlueprintReference] = None, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version. + + :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 body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword definition: The agent definition. This can be a workflow, hosted agent, or a simple + agent definition. Required. + :paramtype definition: ~azure.ai.projects.models.AgentDefinition + :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] + :keyword description: A human-readable description of the agent. Default value is None. + :paramtype description: str + :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. + :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :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.AgentVersionDetails] = kwargs.pop("cls", None) + + if body is _Unset: + if definition is _Unset: + raise TypeError("missing required argument: definition") + body = { + "blueprint_reference": blueprint_reference, + "definition": definition, + "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_agents_create_version_request( + agent_name=agent_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.AgentVersionDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def create_version_from_manifest( + self, + agent_name: str, + *, + manifest_id: str, + parameter_values: dict[str, Any], + content_type: str = "application/json", + metadata: Optional[dict[str, str]] = None, + description: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version from a manifest. + + :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 + :keyword manifest_id: The manifest ID to import the agent version from. Required. + :paramtype manifest_id: str + :keyword parameter_values: The inputs to the manifest that will result in a fully materialized + Agent. Required. + :paramtype parameter_values: dict[str, any] + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: 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] + :keyword description: A human-readable description of the agent. Default value is None. + :paramtype description: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_version_from_manifest( + self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version from a manifest. + + :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 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: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_version_from_manifest( + self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version from a manifest. + + :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 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: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_version_from_manifest( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + manifest_id: str = _Unset, + parameter_values: dict[str, Any] = _Unset, + metadata: Optional[dict[str, str]] = None, + description: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """Create a new agent version from a manifest. + + :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 body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword manifest_id: The manifest ID to import the agent version from. Required. + :paramtype manifest_id: str + :keyword parameter_values: The inputs to the manifest that will result in a fully materialized + Agent. Required. + :paramtype parameter_values: dict[str, any] + :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] + :keyword description: A human-readable description of the agent. Default value is None. + :paramtype description: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :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.AgentVersionDetails] = kwargs.pop("cls", None) + + if body is _Unset: + if manifest_id is _Unset: + raise TypeError("missing required argument: manifest_id") + if parameter_values is _Unset: + raise TypeError("missing required argument: parameter_values") + body = { + "description": description, + "manifest_id": manifest_id, + "metadata": metadata, + "parameter_values": parameter_values, + } + 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_agents_create_version_from_manifest_request( + agent_name=agent_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.AgentVersionDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _models.AgentVersionDetails: + """Retrieves a specific version of an agent. + + :param agent_name: The name of the agent to retrieve. Required. + :type agent_name: str + :param agent_version: The version of the agent to retrieve. Required. + :type agent_version: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :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.AgentVersionDetails] = kwargs.pop("cls", None) + + _request = build_agents_get_version_request( + agent_name=agent_name, + agent_version=agent_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) + 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.AgentVersionDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete_version( + self, agent_name: str, agent_version: str, *, force: Optional[bool] = None, **kwargs: Any + ) -> _models.DeleteAgentVersionResponse: + """Deletes a specific version of an agent. For hosted agents, if the version has active sessions, + the request is rejected with HTTP 409 unless ``force`` is set to true. When force is true, all + sessions associated with this version are cascade-deleted. + + :param agent_name: The name of the agent to delete. Required. + :type agent_name: str + :param agent_version: The version of the agent to delete. Required. + :type agent_version: str + :keyword force: For Hosted Agents, if true, force-deletes the version even if it has active + sessions, cascading deletion to all associated sessions. Defaults to ``false``. This value is + not relevant for other Agent types. Default value is None. + :paramtype force: bool + :return: DeleteAgentVersionResponse. The DeleteAgentVersionResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.DeleteAgentVersionResponse + :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.DeleteAgentVersionResponse] = kwargs.pop("cls", None) + + _request = build_agents_delete_version_request( + agent_name=agent_name, + agent_version=agent_version, + force=force, + 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.DeleteAgentVersionResponse, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_versions( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.AgentVersionDetails"]: + """Returns the list of versions of an agent. + + :param agent_name: The name of the agent to retrieve versions for. 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 AgentVersionDetails + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.AgentVersionDetails] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.AgentVersionDetails]] = 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_agents_list_versions_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.AgentVersionDetails], + 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) + + +class EvaluationRulesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`evaluation_rules` 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, id: str, **kwargs: Any) -> _models.EvaluationRule: + """Get an evaluation rule. + + :param id: Unique identifier for the evaluation rule. Required. + :type id: str + :return: EvaluationRule. The EvaluationRule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationRule + :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.EvaluationRule] = kwargs.pop("cls", None) + + _request = build_evaluation_rules_get_request( + id=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 + + 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.EvaluationRule, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete(self, id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete an evaluation rule. + + :param id: Unique identifier for the evaluation rule. Required. + :type 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_evaluation_rules_delete_request( + id=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 + + @overload + def create_or_update( + self, id: str, evaluation_rule: _models.EvaluationRule, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationRule: + """Create or update an evaluation rule. + + :param id: Unique identifier for the evaluation rule. Required. + :type id: str + :param evaluation_rule: Evaluation rule resource. Required. + :type evaluation_rule: ~azure.ai.projects.models.EvaluationRule + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationRule. The EvaluationRule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationRule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, id: str, evaluation_rule: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationRule: + """Create or update an evaluation rule. + + :param id: Unique identifier for the evaluation rule. Required. + :type id: str + :param evaluation_rule: Evaluation rule resource. Required. + :type evaluation_rule: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationRule. The EvaluationRule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationRule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, id: str, evaluation_rule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationRule: + """Create or update an evaluation rule. + + :param id: Unique identifier for the evaluation rule. Required. + :type id: str + :param evaluation_rule: Evaluation rule resource. Required. + :type evaluation_rule: 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: EvaluationRule. The EvaluationRule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationRule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_or_update( + self, id: str, evaluation_rule: Union[_models.EvaluationRule, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationRule: + """Create or update an evaluation rule. + + :param id: Unique identifier for the evaluation rule. Required. + :type id: str + :param evaluation_rule: Evaluation rule resource. Is one of the following types: + EvaluationRule, JSON, IO[bytes] Required. + :type evaluation_rule: ~azure.ai.projects.models.EvaluationRule or JSON or IO[bytes] + :return: EvaluationRule. The EvaluationRule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationRule + :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.EvaluationRule] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(evaluation_rule, (IOBase, bytes)): + _content = evaluation_rule + else: + _content = json.dumps(evaluation_rule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_evaluation_rules_create_or_update_request( + id=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, 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.EvaluationRule, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + action_type: Optional[Union[str, _models.EvaluationRuleActionType]] = None, + agent_name: Optional[str] = None, + enabled: Optional[bool] = None, + **kwargs: Any + ) -> ItemPaged["_models.EvaluationRule"]: + """List all evaluation rules. + + :keyword action_type: Filter by the type of evaluation rule. Known values are: + "continuousEvaluation" and "humanEvaluationPreview". Default value is None. + :paramtype action_type: str or ~azure.ai.projects.models.EvaluationRuleActionType + :keyword agent_name: Filter by the agent name. Default value is None. + :paramtype agent_name: str + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of EvaluationRule + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluationRule] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.EvaluationRule]] = 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_evaluation_rules_list_request( + action_type=action_type, + agent_name=agent_name, + 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 + ) + 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.EvaluationRule], + 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 ConnectionsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`connections` 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.Connection: + """Get a connection by name, without populating connection credentials. + + :param name: The friendly name of the connection, provided by the user. Required. + :type name: str + :return: Connection. The Connection is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Connection + :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.Connection] = kwargs.pop("cls", None) + + _request = build_connections_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: + 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["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.Connection, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def _get_with_credentials(self, name: str, **kwargs: Any) -> _models.Connection: + """Get a connection by name, with its connection credentials. + + :param name: The friendly name of the connection, provided by the user. Required. + :type name: str + :return: Connection. The Connection is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Connection + :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.Connection] = kwargs.pop("cls", None) + + _request = build_connections_get_with_credentials_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) + raise HttpResponseError(response=response) + + response_headers = {} + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.Connection, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + connection_type: Optional[Union[str, _models.ConnectionType]] = None, + default_connection: Optional[bool] = None, + **kwargs: Any + ) -> ItemPaged["_models.Connection"]: + """List all connections in the project, without populating connection credentials. + + :keyword connection_type: List connections of this specific type. Known values are: + "AzureOpenAI", "AzureBlob", "AzureStorageAccount", "CognitiveSearch", "CosmosDB", "ApiKey", + "AppConfig", "AppInsights", "CustomKeys", and "RemoteTool_Preview". Default value is None. + :paramtype connection_type: str or ~azure.ai.projects.models.ConnectionType + :keyword default_connection: List connections that are default connections. Default value is + None. + :paramtype default_connection: bool + :return: An iterator like instance of Connection + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Connection] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.Connection]] = 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_connections_list_request( + connection_type=connection_type, + default_connection=default_connection, + 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.Connection], + 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 DatasetsOperations: + """ + .. 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 list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.DatasetVersion"]: + """List all versions of the given DatasetVersion. + + :param name: The name of the resource. Required. + :type name: str + :return: An iterator like instance of DatasetVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.DatasetVersion] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.DatasetVersion]] = 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_datasets_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 + ) + 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.DatasetVersion], + 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.DatasetVersion"]: + """List the latest version of each DatasetVersion. + + :return: An iterator like instance of DatasetVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.DatasetVersion] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.DatasetVersion]] = 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_datasets_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.DatasetVersion], + 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.DatasetVersion: + """Get the specific version of the DatasetVersion. The service returns 404 Not Found error if the + DatasetVersion does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to retrieve. Required. + :type version: str + :return: DatasetVersion. The DatasetVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetVersion + :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.DatasetVersion] = kwargs.pop("cls", None) + + _request = build_datasets_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.DatasetVersion, 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 DatasetVersion. The service returns 204 No Content if the + DatasetVersion was deleted successfully or if the DatasetVersion does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the DatasetVersion 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_datasets_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 create_or_update( + self, + name: str, + version: str, + dataset_version: _models.DatasetVersion, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.DatasetVersion: + """Create a new or update an existing DatasetVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to create or update. Required. + :type version: str + :param dataset_version: The DatasetVersion to create or update. Required. + :type dataset_version: ~azure.ai.projects.models.DatasetVersion + :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: DatasetVersion. The DatasetVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, + name: str, + version: str, + dataset_version: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.DatasetVersion: + """Create a new or update an existing DatasetVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to create or update. Required. + :type version: str + :param dataset_version: The DatasetVersion to create or update. Required. + :type dataset_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: DatasetVersion. The DatasetVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, + name: str, + version: str, + dataset_version: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.DatasetVersion: + """Create a new or update an existing DatasetVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to create or update. Required. + :type version: str + :param dataset_version: The DatasetVersion to create or update. Required. + :type dataset_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: DatasetVersion. The DatasetVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_or_update( + self, name: str, version: str, dataset_version: Union[_models.DatasetVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DatasetVersion: + """Create a new or update an existing DatasetVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to create or update. Required. + :type version: str + :param dataset_version: The DatasetVersion to create or update. Is one of the following types: + DatasetVersion, JSON, IO[bytes] Required. + :type dataset_version: ~azure.ai.projects.models.DatasetVersion or JSON or IO[bytes] + :return: DatasetVersion. The DatasetVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetVersion + :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.DatasetVersion] = kwargs.pop("cls", None) + + content_type = content_type or "application/merge-patch+json" + _content = None + if isinstance(dataset_version, (IOBase, bytes)): + _content = dataset_version + else: + _content = json.dumps(dataset_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_datasets_create_or_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.DatasetVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: _models.PendingUploadRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of a dataset for a specific version. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: ~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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of a dataset for a specific version. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of a dataset for a specific version. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: 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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: Union[_models.PendingUploadRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of a dataset for a specific version. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Is one of the following + types: PendingUploadRequest, JSON, IO[bytes] Required. + :type pending_upload_request: ~azure.ai.projects.models.PendingUploadRequest or JSON or + IO[bytes] + :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :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.PendingUploadResponse] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(pending_upload_request, (IOBase, bytes)): + _content = pending_upload_request + else: + _content = json.dumps(pending_upload_request, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_datasets_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.PendingUploadResponse, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get_credentials(self, name: str, version: str, **kwargs: Any) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with a Dataset version. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the DatasetVersion to operate on. Required. + :type version: str + :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 = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) + + _request = build_datasets_get_credentials_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.DatasetCredential, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +class DeploymentsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`deployments` 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.Deployment: + """Get a deployed model. + + :param name: Name of the deployment. Required. + :type name: str + :return: Deployment. The Deployment is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Deployment + :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.Deployment] = kwargs.pop("cls", None) + + _request = build_deployments_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: + 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["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.Deployment, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + model_publisher: Optional[str] = None, + model_name: Optional[str] = None, + deployment_type: Optional[Union[str, _models.DeploymentType]] = None, + **kwargs: Any + ) -> ItemPaged["_models.Deployment"]: + """List all deployed models in the project. + + :keyword model_publisher: Model publisher to filter models by. Default value is None. + :paramtype model_publisher: str + :keyword model_name: Model name (the publisher specific name) to filter models by. Default + value is None. + :paramtype model_name: str + :keyword deployment_type: Type of deployment to filter list by. "ModelDeployment" Default value + is None. + :paramtype deployment_type: str or ~azure.ai.projects.models.DeploymentType + :return: An iterator like instance of Deployment + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Deployment] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.Deployment]] = 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_deployments_list_request( + model_publisher=model_publisher, + model_name=model_name, + deployment_type=deployment_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 + ) + 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.Deployment], + 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 IndexesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`indexes` 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.Index"]: + """List all versions of the given Index. + + :param name: The name of the resource. Required. + :type name: str + :return: An iterator like instance of Index + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Index] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.Index]] = 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_indexes_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 + ) + 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.Index], + 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.Index"]: + """List the latest version of each Index. + + :return: An iterator like instance of Index + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Index] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.Index]] = 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_indexes_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.AgentDetails], - 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 extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.Index], + 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.Index: + """Get the specific version of the Index. The service returns 404 Not Found error if the Index + does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the Index to retrieve. Required. + :type version: str + :return: Index. The Index is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Index + :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.Index] = kwargs.pop("cls", None) + + _request = build_indexes_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.Index, 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 Index. The service returns 204 No Content if the Index was + deleted successfully or if the Index does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the Index 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_indexes_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 create_or_update( + self, + name: str, + version: str, + index: _models.Index, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.Index: + """Create a new or update an existing Index with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the Index to create or update. Required. + :type version: str + :param index: The Index to create or update. Required. + :type index: ~azure.ai.projects.models.Index + :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: Index. The Index is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Index + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, name: str, version: str, index: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.Index: + """Create a new or update an existing Index with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the Index to create or update. Required. + :type version: str + :param index: The Index to create or update. Required. + :type index: 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: Index. The Index is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Index + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, + name: str, + version: str, + index: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.Index: + """Create a new or update an existing Index with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the Index to create or update. Required. + :type version: str + :param index: The Index to create or update. Required. + :type index: 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: Index. The Index is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Index + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_or_update( + self, name: str, version: str, index: Union[_models.Index, JSON, IO[bytes]], **kwargs: Any + ) -> _models.Index: + """Create a new or update an existing Index with the given version id. - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the Index to create or update. Required. + :type version: str + :param index: The Index to create or update. Is one of the following types: Index, JSON, + IO[bytes] Required. + :type index: ~azure.ai.projects.models.Index or JSON or IO[bytes] + :return: Index. The Index is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Index + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - 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) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Index] = kwargs.pop("cls", None) + + content_type = content_type or "application/merge-patch+json" + _content = None + if isinstance(index, (IOBase, bytes)): + _content = index + else: + _content = json.dumps(index, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_indexes_create_or_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.Index, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +class BetaAgentsOperations: # pylint: disable=too-many-public-methods + """ + .. 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 patch_agent_details( + self, + agent_name: str, + *, + 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. + + :param agent_name: The name of the agent to retrieve. Required. + :type agent_name: str + :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 + :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. + + :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/merge-patch+json". + :paramtype content_type: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :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. + + :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/merge-patch+json". + :paramtype content_type: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def patch_agent_details( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, + agent_card: Optional[_models.AgentCard] = None, + **kwargs: Any + ) -> _models.AgentDetails: + """Updates an agent endpoint. + + :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 + :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.AgentDetails] = 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 + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_agents_patch_agent_details_request( + agent_name=agent_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) - return pipeline_response + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.AgentDetails, response.json()) - return ItemPaged(get_next, extract_data) + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @overload - def create_version( + def create_version_from_code( self, agent_name: str, + content: _models.CreateAgentVersionFromCodeContent, *, - definition: _models.AgentDefinition, - content_type: str = "application/json", - metadata: Optional[dict[str, str]] = None, - description: Optional[str] = None, - blueprint_reference: Optional[_models.AgentBlueprintReference] = None, + code_zip_sha256: str, **kwargs: Any ) -> _models.AgentVersionDetails: - """Create a new agent version. + """create_version_from_code. :param agent_name: The unique name that identifies the agent. Name can be used to retrieve/update/delete the agent. @@ -2598,33 +6639,21 @@ def create_version( * Can contain hyphens in the middle * Must not exceed 63 characters. Required. :type agent_name: str - :keyword definition: The agent definition. This can be a workflow, hosted agent, or a simple - agent definition. Required. - :paramtype definition: ~azure.ai.projects.models.AgentDefinition - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: 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] - :keyword description: A human-readable description of the agent. Default value is None. - :paramtype description: str - :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. - :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference + :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_version( - self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + def create_version_from_code( + self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any ) -> _models.AgentVersionDetails: - """Create a new agent version. + """create_version_from_code. :param agent_name: The unique name that identifies the agent. Name can be used to retrieve/update/delete the agent. @@ -2633,21 +6662,26 @@ def create_version( * Can contain hyphens in the middle * Must not exceed 63 characters. 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 + :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: """ - @overload - def create_version( - self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + @distributed_trace + def create_version_from_code( + self, + agent_name: str, + content: Union[_models.CreateAgentVersionFromCodeContent, JSON], + *, + code_zip_sha256: str, + **kwargs: Any ) -> _models.AgentVersionDetails: - """Create a new agent version. + """create_version_from_code. :param agent_name: The unique name that identifies the agent. Name can be used to retrieve/update/delete the agent. @@ -2656,55 +6690,274 @@ def create_version( * 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 + :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.AgentVersionDetails] = 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) + + _request = build_beta_agents_create_version_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, + ) + 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.AgentVersionDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def download_code(self, agent_name: str, *, agent_version: Optional[str] = None, **kwargs: Any) -> Iterator[bytes]: + """Download the code zip for a code-based hosted agent. + Returns the previously-uploaded zip (``application/zip``). + + If ``agent_version`` is supplied, returns that version's code zip; otherwise + returns the latest version's code zip. + + The SHA-256 digest of the returned bytes matches the ``content_hash`` on the + resolved version's ``code_configuration``. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :keyword agent_version: The version of the agent whose code zip should be downloaded. + If omitted, the latest version's code zip is returned. Default value is None. + :paramtype agent_version: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] + :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[Iterator[bytes]] = kwargs.pop("cls", None) + + _request = build_beta_agents_download_code_request( + agent_name=agent_name, + agent_version=agent_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", 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 [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) + + response_headers = {} + response_headers["x-ms-agent-version"] = self._deserialize("str", response.headers.get("x-ms-agent-version")) + 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 + + @overload + def create_session( + self, + agent_name: str, + *, + version_indicator: _models.VersionIndicator, + user_isolation_key: Optional[str] = None, + 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 user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :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, + *, + user_isolation_key: Optional[str] = None, + 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 user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :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], + *, + user_isolation_key: Optional[str] = None, + 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 user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_version( + def create_session( self, agent_name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - definition: _models.AgentDefinition = _Unset, - metadata: Optional[dict[str, str]] = None, - description: Optional[str] = None, - blueprint_reference: Optional[_models.AgentBlueprintReference] = None, + version_indicator: _models.VersionIndicator = _Unset, + user_isolation_key: Optional[str] = None, + agent_session_id: Optional[str] = None, **kwargs: Any - ) -> _models.AgentVersionDetails: - """Create a new agent version. - - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + ) -> _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. - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. + :param agent_name: The name of the agent to create a session for. 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 definition: The agent definition. This can be a workflow, hosted agent, or a simple - agent definition. Required. - :paramtype definition: ~azure.ai.projects.models.AgentDefinition - :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] - :keyword description: A human-readable description of the agent. Default value is None. - :paramtype description: str - :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. - :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :keyword version_indicator: Determines which agent version backs the session. Required. + :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: 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: """ error_map: MutableMapping = { @@ -2719,17 +6972,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.AgentVersionDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) if body is _Unset: - if definition is _Unset: - raise TypeError("missing required argument: definition") - body = { - "blueprint_reference": blueprint_reference, - "definition": definition, - "description": description, - "metadata": metadata, - } + 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 @@ -2738,178 +6986,325 @@ def create_version( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_agents_create_version_request( - agent_name=agent_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 = build_beta_agents_create_session_request( + agent_name=agent_name, + user_isolation_key=user_isolation_key, + 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.AgentSessionResource, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get_session( + self, agent_name: str, session_id: str, *, user_isolation_key: Optional[str] = None, **kwargs: Any + ) -> _models.AgentSessionResource: + """Retrieves a session by ID. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param session_id: The session identifier. Required. + :type session_id: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :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.AgentSessionResource] = kwargs.pop("cls", None) + + _request = build_beta_agents_get_session_request( + agent_name=agent_name, + session_id=session_id, + user_isolation_key=user_isolation_key, + 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.AgentSessionResource, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete_session( # pylint: disable=inconsistent-return-statements + self, agent_name: str, session_id: str, *, user_isolation_key: Optional[str] = None, **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 session_id: The session identifier. Required. + :type session_id: str + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: 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_agents_delete_session_request( + agent_name=agent_name, + session_id=session_id, + user_isolation_key=user_isolation_key, + 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_sessions( + self, + agent_name: str, + *, + user_isolation_key: Optional[str] = None, + 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 + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: 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] + :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, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + error_map.update(kwargs.pop("error_map", {}) or {}) - _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 prepare_request(_continuation_token=None): - response = pipeline_response.http_response + _request = build_beta_agents_list_sessions_request( + agent_name=agent_name, + user_isolation_key=user_isolation_key, + 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 - 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, + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.AgentSessionResource], + deserialized.get("data", []), ) - raise HttpResponseError(response=response, model=error) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.AgentVersionDetails, response.json()) + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - return 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) - @overload - def create_version_from_manifest( - self, - agent_name: str, - *, - manifest_id: str, - parameter_values: dict[str, Any], - content_type: str = "application/json", - metadata: Optional[dict[str, str]] = None, - description: Optional[str] = None, - **kwargs: Any - ) -> _models.AgentVersionDetails: - """Create a new agent version from a manifest. + return pipeline_response - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + return ItemPaged(get_next, extract_data) - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :keyword manifest_id: The manifest ID to import the agent version from. Required. - :paramtype manifest_id: str - :keyword parameter_values: The inputs to the manifest that will result in a fully materialized - Agent. Required. - :paramtype parameter_values: dict[str, any] - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: 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. + @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. - 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] - :keyword description: A human-readable description of the agent. Default value is None. - :paramtype description: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + Each SSE frame contains: - @overload - def create_version_from_manifest( - self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentVersionDetails: - """Create a new agent version from a manifest. + * `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 agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + Example SSE frames: - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. 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: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + .. code-block:: - @overload - def create_version_from_manifest( - self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentVersionDetails: - """Create a new agent version from a manifest. + event: log + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + event: log + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. 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: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + event: log + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} - @distributed_trace - def create_version_from_manifest( - self, - agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - manifest_id: str = _Unset, - parameter_values: dict[str, Any] = _Unset, - metadata: Optional[dict[str, str]] = None, - description: Optional[str] = None, - **kwargs: Any - ) -> _models.AgentVersionDetails: - """Create a new agent version from a manifest. + event: log + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + The stream remains open until the client disconnects or the server + terminates the connection. Clients should handle reconnection as needed. - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. + :param agent_name: The name of the hosted agent. 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 manifest_id: The manifest ID to import the agent version from. Required. - :paramtype manifest_id: str - :keyword parameter_values: The inputs to the manifest that will result in a fully materialized - Agent. Required. - :paramtype parameter_values: dict[str, any] - :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] - :keyword description: A human-readable description of the agent. Default value is None. - :paramtype description: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :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 = { @@ -2920,36 +7315,16 @@ def create_version_from_manifest( } 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.AgentVersionDetails] = kwargs.pop("cls", None) - - if body is _Unset: - if manifest_id is _Unset: - raise TypeError("missing required argument: manifest_id") - if parameter_values is _Unset: - raise TypeError("missing required argument: parameter_values") - body = { - "description": description, - "manifest_id": manifest_id, - "metadata": metadata, - "parameter_values": parameter_values, - } - 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[_models.SessionLogEvent] = kwargs.pop("cls", None) - _request = build_agents_create_version_from_manifest_request( + _request = build_beta_agents_get_session_log_stream_request( agent_name=agent_name, - content_type=content_type, + agent_version=agent_version, + session_id=session_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -2959,7 +7334,7 @@ def create_version_from_manifest( _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 ) @@ -2979,26 +7354,47 @@ def create_version_from_manifest( ) 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.AgentVersionDetails, 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 get_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _models.AgentVersionDetails: - """Retrieves a specific version of an agent. + def _upload_session_file( + self, + agent_name: str, + agent_session_id: str, + content: bytes, + *, + path: str, + user_isolation_key: Optional[str] = None, + **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 agent_name: The name of the agent to retrieve. Required. + :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_version: The version of the agent to retrieve. Required. - :type agent_version: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :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 + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SessionFileWriteResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3009,15 +7405,22 @@ def get_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _mo } 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: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) + cls: ClsType[_models.SessionFileWriteResult] = kwargs.pop("cls", None) - _request = build_agents_get_version_request( + _content = content + + _request = build_beta_agents_upload_session_file_request( agent_name=agent_name, - agent_version=agent_version, + agent_session_id=agent_session_id, + path=path, + user_isolation_key=user_isolation_key, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -3034,7 +7437,7 @@ def get_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _mo 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 @@ -3050,7 +7453,7 @@ def get_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _mo if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentVersionDetails, response.json()) + deserialized = _deserialize(_models.SessionFileWriteResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3058,16 +7461,29 @@ def get_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _mo return deserialized # type: ignore @distributed_trace - def delete_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _models.DeleteAgentVersionResponse: - """Deletes a specific version of an agent. + def download_session_file( + self, + agent_name: str, + agent_session_id: str, + *, + path: str, + user_isolation_key: Optional[str] = None, + **kwargs: Any + ) -> Iterator[bytes]: + """Download a file from the session sandbox as a binary stream. - :param agent_name: The name of the agent to delete. Required. + :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_version: The version of the agent to delete. Required. - :type agent_version: str - :return: DeleteAgentVersionResponse. The DeleteAgentVersionResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.DeleteAgentVersionResponse + :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 + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3081,11 +7497,13 @@ def delete_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteAgentVersionResponse] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_agents_delete_version_request( + _request = build_beta_agents_download_session_file_request( agent_name=agent_name, - agent_version=agent_version, + agent_session_id=agent_session_id, + path=path, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3096,7 +7514,7 @@ def delete_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> _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 ) @@ -3116,10 +7534,7 @@ def delete_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DeleteAgentVersionResponse, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3127,125 +7542,30 @@ def delete_version(self, agent_name: str, agent_version: str, **kwargs: Any) -> return deserialized # type: ignore @distributed_trace - def list_versions( + def get_session_files( self, agent_name: str, + agent_session_id: str, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + path: str, + user_isolation_key: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.AgentVersionDetails"]: - """Returns the list of versions of an agent. + ) -> _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 agent_name: The name of the agent to retrieve versions for. Required. + :param agent_name: The name of the agent. 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 AgentVersionDetails - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.AgentVersionDetails] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.AgentVersionDetails]] = 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_agents_list_versions_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.AgentVersionDetails], - 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) - - -class EvaluationRulesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`evaluation_rules` 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, id: str, **kwargs: Any) -> _models.EvaluationRule: - """Get an evaluation rule. - - :param id: Unique identifier for the evaluation rule. Required. - :type id: str - :return: EvaluationRule. The EvaluationRule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationRule + :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 + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str + :return: SessionDirectoryListResult. The SessionDirectoryListResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.SessionDirectoryListResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3259,10 +7579,13 @@ def get(self, id: str, **kwargs: Any) -> _models.EvaluationRule: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluationRule] = kwargs.pop("cls", None) + cls: ClsType[_models.SessionDirectoryListResult] = kwargs.pop("cls", None) - _request = build_evaluation_rules_get_request( - id=id, + _request = build_beta_agents_get_session_files_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3287,12 +7610,16 @@ def get(self, id: str, **kwargs: Any) -> _models.EvaluationRule: 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.EvaluationRule, response.json()) + deserialized = _deserialize(_models.SessionDirectoryListResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3300,11 +7627,32 @@ def get(self, id: str, **kwargs: Any) -> _models.EvaluationRule: return deserialized # type: ignore @distributed_trace - def delete(self, id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete an evaluation rule. + def delete_session_file( # pylint: disable=inconsistent-return-statements + self, + agent_name: str, + agent_session_id: str, + *, + path: str, + recursive: Optional[bool] = None, + user_isolation_key: Optional[str] = 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 id: Unique identifier for the evaluation rule. Required. - :type id: str + :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 + :keyword user_isolation_key: Opaque per-user isolation key used to scope endpoint-scoped data + (responses, conversations, sessions) to a specific end user. Default value is None. + :paramtype user_isolation_key: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -3322,8 +7670,12 @@ def delete(self, id: str, **kwargs: Any) -> None: # pylint: disable=inconsisten cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_evaluation_rules_delete_request( - id=id, + _request = build_beta_agents_delete_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, + recursive=recursive, + user_isolation_key=user_isolation_key, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3342,78 +7694,108 @@ def delete(self, id: str, **kwargs: Any) -> None: # pylint: disable=inconsisten if response.status_code not in [204]: 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 cls: return cls(pipeline_response, None, {}) # type: ignore @overload - def create_or_update( - self, id: str, evaluation_rule: _models.EvaluationRule, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationRule: - """Create or update an evaluation rule. + def create_optimization_job( + self, + job: _models.OptimizationJob, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. - :param id: Unique identifier for the evaluation rule. Required. - :type id: str - :param evaluation_rule: Evaluation rule resource. Required. - :type evaluation_rule: ~azure.ai.projects.models.EvaluationRule + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :param job: The job to create. Required. + :type job: ~azure.ai.projects.models.OptimizationJob + :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: EvaluationRule. The EvaluationRule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationRule + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_or_update( - self, id: str, evaluation_rule: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationRule: - """Create or update an evaluation rule. - - :param id: Unique identifier for the evaluation rule. Required. - :type id: str - :param evaluation_rule: Evaluation rule resource. Required. - :type evaluation_rule: JSON + def create_optimization_job( + self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. + + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :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: EvaluationRule. The EvaluationRule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationRule + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_or_update( - self, id: str, evaluation_rule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationRule: - """Create or update an evaluation rule. + def create_optimization_job( + self, + job: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. - :param id: Unique identifier for the evaluation rule. Required. - :type id: str - :param evaluation_rule: Evaluation rule resource. Required. - :type evaluation_rule: IO[bytes] + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :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: EvaluationRule. The EvaluationRule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationRule + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_or_update( - self, id: str, evaluation_rule: Union[_models.EvaluationRule, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationRule: - """Create or update an evaluation rule. + def create_optimization_job( + self, job: Union[_models.OptimizationJob, JSON, IO[bytes]], *, operation_id: Optional[str] = None, **kwargs: Any + ) -> _models.OptimizationJob: + """Creates an agent optimization job. - :param id: Unique identifier for the evaluation rule. Required. - :type id: str - :param evaluation_rule: Evaluation rule resource. Is one of the following types: - EvaluationRule, JSON, IO[bytes] Required. - :type evaluation_rule: ~azure.ai.projects.models.EvaluationRule or JSON or IO[bytes] - :return: EvaluationRule. The EvaluationRule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationRule + Create an optimization job. Returns 201 with the queued job. Honours ``Operation-Id`` for + idempotent retry. + + :param job: The job to create. Is one of the following types: OptimizationJob, JSON, IO[bytes] + Required. + :type job: ~azure.ai.projects.models.OptimizationJob 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: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3428,17 +7810,17 @@ 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.EvaluationRule] = kwargs.pop("cls", None) + cls: ClsType[_models.OptimizationJob] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(evaluation_rule, (IOBase, bytes)): - _content = evaluation_rule + if isinstance(job, (IOBase, bytes)): + _content = job else: - _content = json.dumps(evaluation_rule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_evaluation_rules_create_or_update_request( - id=id, + _request = build_beta_agents_create_optimization_job_request( + operation_id=operation_id, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -3458,51 +7840,146 @@ def create_or_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) + + 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.EvaluationRule, response.json()) + deserialized = _deserialize(_models.OptimizationJob, 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( + def get_optimization_job(self, job_id: str, **kwargs: Any) -> _models.OptimizationJob: + """Get info about an agent optimization job. + + Get an optimization job by id. Emits ``Retry-After`` while the job is non-terminal. + + :param job_id: The ID of the job. Required. + :type job_id: str + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob + :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.OptimizationJob] = kwargs.pop("cls", None) + + _request = build_beta_agents_get_optimization_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 + + 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) + + 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.OptimizationJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_optimization_jobs( self, *, - action_type: Optional[Union[str, _models.EvaluationRuleActionType]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.JobStatus]] = None, agent_name: Optional[str] = None, - enabled: Optional[bool] = None, **kwargs: Any - ) -> ItemPaged["_models.EvaluationRule"]: - """List all evaluation rules. + ) -> ItemPaged["_models.OptimizationJob"]: + """Returns a list of agent optimization jobs. - :keyword action_type: Filter by the type of evaluation rule. Known values are: - "continuousEvaluation" and "humanEvaluationPreview". Default value is None. - :paramtype action_type: str or ~azure.ai.projects.models.EvaluationRuleActionType - :keyword agent_name: Filter by the agent name. Default value is None. + List optimization jobs. Supports cursor pagination and optional ``status`` / ``agent_name`` + filters. + + :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 status: Filter to jobs in this lifecycle state. Known values are: "queued", + "in_progress", "succeeded", "failed", and "cancelled". Default value is None. + :paramtype status: str or ~azure.ai.projects.models.JobStatus + :keyword agent_name: Filter to jobs targeting this agent name. Default value is None. :paramtype agent_name: str - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of EvaluationRule - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluationRule] + :return: An iterator like instance of OptimizationJob + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.OptimizationJob] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.EvaluationRule]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.OptimizationJob]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -3512,58 +7989,37 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_evaluation_rules_list_request( - action_type=action_type, - agent_name=agent_name, - 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 - ) - 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_agents_list_optimization_jobs_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + status=status, + 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) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.EvaluationRule], - deserialized.get("value", []), + List[_models.OptimizationJob], + 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 @@ -3573,38 +8029,26 @@ 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) - -class ConnectionsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`connections` 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.Connection: - """Get a connection by name, without populating connection credentials. + def cancel_optimization_job(self, job_id: str, **kwargs: Any) -> _models.OptimizationJob: + """Cancels an agent optimization job. - :param name: The friendly name of the connection, provided by the user. Required. - :type name: str - :return: Connection. The Connection is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Connection + Request cancellation. Idempotent on terminal states. + + :param job_id: The ID of the job to cancel. Required. + :type job_id: str + :return: OptimizationJob. The OptimizationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3618,10 +8062,10 @@ def _get(self, name: str, **kwargs: Any) -> _models.Connection: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Connection] = kwargs.pop("cls", None) + cls: ClsType[_models.OptimizationJob] = kwargs.pop("cls", None) - _request = build_connections_get_request( - name=name, + _request = build_beta_agents_cancel_optimization_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3646,31 +8090,34 @@ def _get(self, name: str, **kwargs: Any) -> _models.Connection: 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["x-ms-client-request-id"] = self._deserialize( - "str", response.headers.get("x-ms-client-request-id") - ) + 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.Connection, response.json()) + deserialized = _deserialize(_models.OptimizationJob, 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 _get_with_credentials(self, name: str, **kwargs: Any) -> _models.Connection: - """Get a connection by name, with its connection credentials. + def delete_optimization_job( # pylint: disable=inconsistent-return-statements + self, job_id: str, **kwargs: Any + ) -> None: + """Deletes an agent optimization job. - :param name: The friendly name of the connection, provided by the user. Required. - :type name: str - :return: Connection. The Connection is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Connection + Delete the job and its candidate artifacts. Cancels first if non-terminal. + + :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 = { @@ -3684,10 +8131,10 @@ def _get_with_credentials(self, name: str, **kwargs: Any) -> _models.Connection: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Connection] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_connections_get_with_credentials_request( - name=name, + _request = build_beta_agents_delete_optimization_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3697,64 +8144,66 @@ def _get_with_credentials(self, name: str, **kwargs: Any) -> _models.Connection: } _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) - raise HttpResponseError(response=response) - - response_headers = {} - response_headers["x-ms-client-request-id"] = self._deserialize( - "str", response.headers.get("x-ms-client-request-id") - ) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.Connection, response.json()) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def list( + def list_optimization_candidates( self, + job_id: str, *, - connection_type: Optional[Union[str, _models.ConnectionType]] = None, - default_connection: Optional[bool] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.Connection"]: - """List all connections in the project, without populating connection credentials. + ) -> _models.AgentsPagedResultOptimizationCandidate: + """Returns a list of candidates for an optimization job. - :keyword connection_type: List connections of this specific type. Known values are: - "AzureOpenAI", "AzureBlob", "AzureStorageAccount", "CognitiveSearch", "CosmosDB", "ApiKey", - "AppConfig", "AppInsights", "CustomKeys", and "RemoteTool_Preview". Default value is None. - :paramtype connection_type: str or ~azure.ai.projects.models.ConnectionType - :keyword default_connection: List connections that are default connections. Default value is - None. - :paramtype default_connection: bool - :return: An iterator like instance of Connection - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Connection] + List candidates produced by a job. + + :param job_id: The optimization job id. Required. + :type job_id: 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 after: A cursor for use in pagination. ``after`` 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 after=obj_foo in order to fetch the next page of the list. Default + value is None. + :paramtype after: str + :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: AgentsPagedResultOptimizationCandidate. The AgentsPagedResultOptimizationCandidate is + compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentsPagedResultOptimizationCandidate :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.Connection]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -3763,191 +8212,73 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_connections_list_request( - connection_type=connection_type, - default_connection=default_connection, - 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.Connection], - 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 DatasetsOperations: - """ - .. 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 list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.DatasetVersion"]: - """List all versions of the given DatasetVersion. - - :param name: The name of the resource. Required. - :type name: str - :return: An iterator like instance of DatasetVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.DatasetVersion] - :raises ~azure.core.exceptions.HttpResponseError: - """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.DatasetVersion]] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentsPagedResultOptimizationCandidate] = kwargs.pop("cls", None) - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, + _request = build_beta_agents_list_optimization_candidates_request( + job_id=job_id, + limit=limit, + order=order, + after=after, + 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), } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(next_link=None): - if not next_link: - - _request = build_datasets_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 - ) - 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 + _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.DatasetVersion], - 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.AgentsPagedResultOptimizationCandidate, 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.DatasetVersion"]: - """List the latest version of each DatasetVersion. - - :return: An iterator like instance of DatasetVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.DatasetVersion] + def get_optimization_candidate( + self, job_id: str, candidate_id: str, **kwargs: Any + ) -> _models.OptimizationCandidate: + """Get a candidate by id. + + Get a single candidate manifest and aggregated evaluation summary. + + :param job_id: The optimization job id. Required. + :type job_id: str + :param candidate_id: The candidate id. Required. + :type candidate_id: str + :return: OptimizationCandidate. The OptimizationCandidate is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.OptimizationCandidate :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.DatasetVersion]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -3956,81 +8287,69 @@ def list(self, **kwargs: Any) -> ItemPaged["_models.DatasetVersion"]: } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_datasets_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) + _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 - ) - 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.OptimizationCandidate] = kwargs.pop("cls", None) - return _request + _request = build_beta_agents_get_optimization_candidate_request( + job_id=job_id, + candidate_id=candidate_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) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.DatasetVersion], - 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.OptimizationCandidate, 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.DatasetVersion: - """Get the specific version of the DatasetVersion. The service returns 404 Not Found error if the - DatasetVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the DatasetVersion to retrieve. Required. - :type version: str - :return: DatasetVersion. The DatasetVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetVersion + def get_optimization_candidate_config( + self, job_id: str, candidate_id: str, **kwargs: Any + ) -> _models.CandidateDeployConfig: + """Get candidate deploy config. + + Get the candidate's deploy config JSON. Used to compose ``agents.create_version(...)`` from a + candidate. + + :param job_id: The optimization job id. Required. + :type job_id: str + :param candidate_id: The candidate id. Required. + :type candidate_id: str + :return: CandidateDeployConfig. The CandidateDeployConfig is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CandidateDeployConfig :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4044,11 +8363,11 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.DatasetVersion: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DatasetVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.CandidateDeployConfig] = kwargs.pop("cls", None) - _request = build_datasets_get_request( - name=name, - version=version, + _request = build_beta_agents_get_optimization_candidate_config_request( + job_id=job_id, + candidate_id=candidate_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4073,12 +8392,16 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.DatasetVersion: 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.DatasetVersion, response.json()) + deserialized = _deserialize(_models.CandidateDeployConfig, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -4086,16 +8409,19 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.DatasetVersion: 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 DatasetVersion. The service returns 204 No Content if the - DatasetVersion was deleted successfully or if the DatasetVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The version of the DatasetVersion to delete. Required. - :type version: str - :return: None - :rtype: None + def get_optimization_candidate_results( + self, job_id: str, candidate_id: str, **kwargs: Any + ) -> _models.CandidateResults: + """Get candidate evaluation results. + + Get full per-task evaluation results for a candidate. + + :param job_id: The optimization job id. Required. + :type job_id: str + :param candidate_id: The candidate id. Required. + :type candidate_id: str + :return: CandidateResults. The CandidateResults is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CandidateResults :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4109,11 +8435,11 @@ 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.CandidateResults] = kwargs.pop("cls", None) - _request = build_datasets_delete_request( - name=name, - version=version, + _request = build_beta_agents_get_optimization_candidate_results_request( + job_id=job_id, + candidate_id=candidate_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4123,113 +8449,63 @@ 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 cls: - return cls(pipeline_response, None, {}) # type: ignore + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.CandidateResults, response.json()) - @overload - def create_or_update( - self, - name: str, - version: str, - dataset_version: _models.DatasetVersion, - *, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.DatasetVersion: - """Create a new or update an existing DatasetVersion with the given version id. + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the DatasetVersion to create or update. Required. - :type version: str - :param dataset_version: The DatasetVersion to create or update. Required. - :type dataset_version: ~azure.ai.projects.models.DatasetVersion - :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: DatasetVersion. The DatasetVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ + return deserialized # type: ignore - @overload - def create_or_update( - self, - name: str, - version: str, - dataset_version: JSON, - *, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.DatasetVersion: - """Create a new or update an existing DatasetVersion with the given version id. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the DatasetVersion to create or update. Required. - :type version: str - :param dataset_version: The DatasetVersion to create or update. Required. - :type dataset_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: DatasetVersion. The DatasetVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ +class BetaEvaluationTaxonomiesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - @overload - def create_or_update( - self, - name: str, - version: str, - dataset_version: IO[bytes], - *, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.DatasetVersion: - """Create a new or update an existing DatasetVersion with the given version id. + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`evaluation_taxonomies` attribute. + """ - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the DatasetVersion to create or update. Required. - :type version: str - :param dataset_version: The DatasetVersion to create or update. Required. - :type dataset_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: DatasetVersion. The DatasetVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetVersion - :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") @distributed_trace - def create_or_update( - self, name: str, version: str, dataset_version: Union[_models.DatasetVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.DatasetVersion: - """Create a new or update an existing DatasetVersion with the given version id. + 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 - :param version: The specific version id of the DatasetVersion to create or update. Required. - :type version: str - :param dataset_version: The DatasetVersion to create or update. Is one of the following types: - DatasetVersion, JSON, IO[bytes] Required. - :type dataset_version: ~azure.ai.projects.models.DatasetVersion or JSON or IO[bytes] - :return: DatasetVersion. The DatasetVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4240,25 +8516,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.DatasetVersion] = kwargs.pop("cls", None) - - content_type = content_type or "application/merge-patch+json" - _content = None - if isinstance(dataset_version, (IOBase, bytes)): - _content = dataset_version - else: - _content = json.dumps(dataset_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) - _request = build_datasets_create_or_update_request( + _request = build_beta_evaluation_taxonomies_get_request( name=name, - version=version, - content_type=content_type, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -4275,7 +8540,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 @@ -4287,111 +8552,224 @@ def create_or_update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DatasetVersion, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def pending_upload( - self, - name: str, - version: str, - pending_upload_request: _models.PendingUploadRequest, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.PendingUploadResponse: - """Start a new or get an existing pending upload of a dataset for a specific version. + @distributed_trace + def list( + self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any + ) -> ItemPaged["_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.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.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 + + 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) + + 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 delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete an evaluation taxonomy by name. :param name: The name of the resource. Required. :type name: str - :param version: The specific version id of the DatasetVersion to operate on. Required. - :type version: str - :param pending_upload_request: The pending upload request parameters. Required. - :type pending_upload_request: ~azure.ai.projects.models.PendingUploadRequest + :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_evaluation_taxonomies_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) + + _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 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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResponse + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def pending_upload( - self, - name: str, - version: str, - pending_upload_request: JSON, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.PendingUploadResponse: - """Start a new or get an existing pending upload of a dataset for a specific version. + 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 version: The specific version id of the DatasetVersion to operate on. Required. - :type version: str - :param pending_upload_request: The pending upload request parameters. Required. - :type pending_upload_request: 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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResponse + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ - @overload - def pending_upload( - self, - name: str, - version: str, - pending_upload_request: IO[bytes], - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.PendingUploadResponse: - """Start a new or get an existing pending upload of a dataset for a specific version. + @overload + 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 version: The specific version id of the DatasetVersion to operate on. Required. - :type version: str - :param pending_upload_request: The pending upload request parameters. Required. - :type pending_upload_request: 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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResponse + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def pending_upload( - self, - name: str, - version: str, - pending_upload_request: Union[_models.PendingUploadRequest, JSON, IO[bytes]], - **kwargs: Any - ) -> _models.PendingUploadResponse: - """Start a new or get an existing pending upload of a dataset for a specific version. + 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 version: The specific version id of the DatasetVersion to operate on. Required. - :type version: str - :param pending_upload_request: The pending upload request parameters. Is one of the following - types: PendingUploadRequest, JSON, IO[bytes] Required. - :type pending_upload_request: ~azure.ai.projects.models.PendingUploadRequest or JSON or - IO[bytes] - :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResponse + :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 = { @@ -4406,18 +8784,17 @@ def pending_upload( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.PendingUploadResponse] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(pending_upload_request, (IOBase, bytes)): - _content = pending_upload_request + if isinstance(taxonomy, (IOBase, bytes)): + _content = taxonomy else: - _content = json.dumps(pending_upload_request, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_datasets_pending_upload_request( + _request = build_beta_evaluation_taxonomies_create_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -4437,7 +8814,7 @@ def pending_upload( 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 @@ -4449,23 +8826,80 @@ def pending_upload( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.PendingUploadResponse, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, 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. + + :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 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 + 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 - def get_credentials(self, name: str, version: str, **kwargs: Any) -> _models.DatasetCredential: - """Get the SAS credential to access the storage account associated with a Dataset version. + 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 specific version id of the DatasetVersion to operate on. Required. - :type version: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :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 = { @@ -4476,15 +8910,24 @@ def get_credentials(self, name: str, version: str, **kwargs: Any) -> _models.Dat } 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.DatasetCredential] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) - _request = build_datasets_get_credentials_request( + 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( name=name, - version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -4513,7 +8956,7 @@ def get_credentials(self, name: str, version: str, **kwargs: Any) -> _models.Dat if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DatasetCredential, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -4521,14 +8964,14 @@ def get_credentials(self, name: str, version: str, **kwargs: Any) -> _models.Dat return deserialized # type: ignore -class DeploymentsOperations: +class BetaEvaluatorsOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`deployments` attribute. + :attr:`evaluators` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -4539,15 +8982,34 @@ 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.Deployment: - """Get a deployed model. + 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. - :param name: Name of the deployment. Required. + :param name: The name of the resource. Required. :type name: str - :return: Deployment. The Deployment is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Deployment + :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, @@ -4556,81 +9018,101 @@ def get(self, name: str, **kwargs: Any) -> _models.Deployment: } 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.Deployment] = kwargs.pop("cls", None) + _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) - _request = build_deployments_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.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) - 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) - response_headers = {} - response_headers["x-ms-client-request-id"] = self._deserialize( - "str", response.headers.get("x-ms-client-request-id") - ) + _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.Deployment, 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( self, *, - model_publisher: Optional[str] = None, - model_name: Optional[str] = None, - deployment_type: Optional[Union[str, _models.DeploymentType]] = None, + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, + limit: Optional[int] = None, **kwargs: Any - ) -> ItemPaged["_models.Deployment"]: - """List all deployed models in the project. + ) -> ItemPaged["_models.EvaluatorVersion"]: + """List the latest version of each evaluator. - :keyword model_publisher: Model publisher to filter models by. Default value is None. - :paramtype model_publisher: str - :keyword model_name: Model name (the publisher specific name) to filter models by. Default + :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 model_name: str - :keyword deployment_type: Type of deployment to filter list by. "ModelDeployment" Default value - is None. - :paramtype deployment_type: str or ~azure.ai.projects.models.DeploymentType - :return: An iterator like instance of Deployment - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Deployment] + :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.Deployment]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -4643,10 +9125,9 @@ def list( def prepare_request(next_link=None): if not next_link: - _request = build_deployments_list_request( - model_publisher=model_publisher, - model_name=model_name, - deployment_type=deployment_type, + _request = build_beta_evaluators_list_request( + type=type, + limit=limit, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4669,7 +9150,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( @@ -4683,7 +9167,7 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.Deployment], + List[_models.EvaluatorVersion], deserialized.get("value", []), ) if cls: @@ -4707,125 +9191,353 @@ def get_next(next_link=None): 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. -class IndexesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + :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 {}) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`indexes` 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[_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 list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.Index"]: - """List all versions of the given Index. + 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 - :return: An iterator like instance of Index - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Index] + :param version: The version of the EvaluatorVersion 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[List[_models.Index]] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_evaluators_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 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 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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :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. + + :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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :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. + + :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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :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. + :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 = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, 304: ResourceNotModifiedError, } - error_map.update(kwargs.pop("error_map", {}) or {}) + 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.EvaluatorVersion] = kwargs.pop("cls", None) + + 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_create_version_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 prepare_request(next_link=None): - if not next_link: + _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 + ) - _request = build_indexes_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) + response = pipeline_response.http_response - 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) + 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) - return _request + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Index], - 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 cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - def get_next(next_link=None): - _request = prepare_request(next_link) + return deserialized # type: ignore - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + @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. - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + :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: + """ - return pipeline_response + @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. - return ItemPaged(get_next, extract_data) + :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: + """ - @distributed_trace - def list(self, **kwargs: Any) -> ItemPaged["_models.Index"]: - """List the latest version of each Index. + @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. - :return: An iterator like instance of Index - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Index] + :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: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.Index]] = kwargs.pop("cls", None) + @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. + :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 = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -4834,81 +9546,158 @@ def list(self, **kwargs: Any) -> ItemPaged["_models.Index"]: } 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_indexes_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.EvaluatorVersion] = 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 - ) - 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(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, + ) + 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()) - return _request + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Index], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + return deserialized # type: ignore - def get_next(next_link=None): - _request = prepare_request(next_link) + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: _models.PendingUploadRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: ~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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. - return pipeline_response + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ - return ItemPaged(get_next, extract_data) + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param pending_upload_request: The pending upload request parameters. Required. + :type pending_upload_request: 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: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def get(self, name: str, version: str, **kwargs: Any) -> _models.Index: - """Get the specific version of the Index. The service returns 404 Not Found error if the Index - does not exist. + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: Union[_models.PendingUploadRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.PendingUploadResponse: + """Start a new or get an existing pending upload of an evaluator for a specific version. - :param name: The name of the resource. Required. + :param name: Required. :type name: str - :param version: The specific version id of the Index to retrieve. Required. + :param version: The specific version id of the EvaluatorVersion to operate on. Required. :type version: str - :return: Index. The Index is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Index + :param pending_upload_request: The pending upload request parameters. Is one of the following + types: PendingUploadRequest, JSON, IO[bytes] Required. + :type pending_upload_request: ~azure.ai.projects.models.PendingUploadRequest or JSON or + IO[bytes] + :return: PendingUploadResponse. The PendingUploadResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4919,15 +9708,25 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.Index: } 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.Index] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.PendingUploadResponse] = kwargs.pop("cls", None) - _request = build_indexes_get_request( + content_type = content_type or "application/json" + _content = None + if isinstance(pending_upload_request, (IOBase, bytes)): + _content = pending_upload_request + else: + _content = json.dumps(pending_upload_request, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_evaluators_pending_upload_request( name=name, version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -4951,29 +9750,120 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.Index: 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.Index, response.json()) + deserialized = _deserialize(_models.PendingUploadResponse, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + def get_credentials( + self, + name: str, + version: str, + credential_request: _models.EvaluatorCredentialRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Required. + :type credential_request: ~azure.ai.projects.models.EvaluatorCredentialRequest + :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, + credential_request: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Required. + :type credential_request: 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, + credential_request: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. + + :param name: Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to operate on. Required. + :type version: str + :param credential_request: The credential request parameters. Required. + :type credential_request: 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 delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete the specific version of the Index. The service returns 204 No Content if the Index was - deleted successfully or if the Index does not exist. + def get_credentials( + self, + name: str, + version: str, + credential_request: Union[_models.EvaluatorCredentialRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.DatasetCredential: + """Get the SAS credential to access the storage account associated with an Evaluator version. - :param name: The name of the resource. Required. + :param name: Required. :type name: str - :param version: The version of the Index to delete. Required. + :param version: The specific version id of the EvaluatorVersion to operate on. Required. :type version: str - :return: None - :rtype: None + :param credential_request: The credential request parameters. Is one of the following types: + EvaluatorCredentialRequest, JSON, IO[bytes] Required. + :type credential_request: ~azure.ai.projects.models.EvaluatorCredentialRequest 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 = { @@ -4984,15 +9874,25 @@ def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: dis } 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.DatasetCredential] = kwargs.pop("cls", None) - _request = build_indexes_delete_request( + content_type = content_type or "application/json" + _content = None + if isinstance(credential_request, (IOBase, bytes)): + _content = credential_request + else: + _content = json.dumps(credential_request, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_evaluators_get_credentials_request( name=name, version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -5001,107 +9901,134 @@ 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.DatasetCredential, 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_or_update( + def create_generation_job( self, - name: str, - version: str, - index: _models.Index, + job: _models.EvaluatorGenerationJob, *, - content_type: str = "application/merge-patch+json", + operation_id: Optional[str] = None, + content_type: str = "application/json", **kwargs: Any - ) -> _models.Index: - """Create a new or update an existing Index with the given version id. + ) -> _models.EvaluatorGenerationJob: + """Creates an evaluator generation job. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the Index to create or update. Required. - :type version: str - :param index: The Index to create or update. Required. - :type index: ~azure.ai.projects.models.Index + 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: ~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/merge-patch+json". + Default value is "application/json". :paramtype content_type: str - :return: Index. The Index is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Index + :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_or_update( - self, name: str, version: str, index: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.Index: - """Create a new or update an existing Index with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the Index to create or update. Required. - :type version: str - :param index: The Index to create or update. Required. - :type index: JSON + 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/merge-patch+json". + Default value is "application/json". :paramtype content_type: str - :return: Index. The Index is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Index + :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_or_update( + def create_generation_job( self, - name: str, - version: str, - index: IO[bytes], + job: IO[bytes], *, - content_type: str = "application/merge-patch+json", + operation_id: Optional[str] = None, + content_type: str = "application/json", **kwargs: Any - ) -> _models.Index: - """Create a new or update an existing Index with the given version id. + ) -> _models.EvaluatorGenerationJob: + """Creates an evaluator generation job. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the Index to create or update. Required. - :type version: str - :param index: The Index to create or update. Required. - :type index: IO[bytes] + 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: 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/merge-patch+json". + Default value is "application/json". :paramtype content_type: str - :return: Index. The Index is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Index + :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_or_update( - self, name: str, version: str, index: Union[_models.Index, JSON, IO[bytes]], **kwargs: Any - ) -> _models.Index: - """Create a new or update an existing Index with the given version id. + 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. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the Index to create or update. Required. - :type version: str - :param index: The Index to create or update. Is one of the following types: Index, JSON, + Creates an evaluator generation job. The service generates rubric-based evaluator definitions + from the provided source materials asynchronously. + + :param job: The job to create. Is one of the following types: EvaluatorGenerationJob, JSON, IO[bytes] Required. - :type index: ~azure.ai.projects.models.Index or JSON or IO[bytes] - :return: Index. The Index is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Index + :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 = { @@ -5116,18 +10043,17 @@ 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.Index] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - content_type = content_type or "application/merge-patch+json" + content_type = content_type or "application/json" _content = None - if isinstance(index, (IOBase, bytes)): - _content = index + if isinstance(job, (IOBase, bytes)): + _content = job else: - _content = json.dumps(index, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_indexes_create_or_update_request( - name=name, - version=version, + _request = build_beta_evaluators_create_generation_job_request( + operation_id=operation_id, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -5147,127 +10073,205 @@ def create_or_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) + + 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.Index, response.json()) + deserialized = _deserialize(_models.EvaluatorGenerationJob, 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 get_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: + """Get info about an evaluator generation job. -class BetaAgentsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + Gets the details of an evaluator generation job by its ID. - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`agents` attribute. - """ + :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 {}) - 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") + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - def patch_agent_details( + 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 + + 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) + + 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.EvaluatorGenerationJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_generation_jobs( self, - agent_name: str, *, - content_type: str = "application/merge-patch+json", - agent_endpoint: Optional[_models.AgentEndpoint] = None, - agent_card: Optional[_models.AgentCard] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + ) -> ItemPaged["_models.EvaluatorGenerationJob"]: + """Returns a list of evaluator generation jobs. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :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.AgentEndpoint - :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 + Returns a list of evaluator 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 + :return: An iterator like instance of EvaluatorGenerationJob + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluatorGenerationJob] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @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. + cls: ClsType[List[_models.EvaluatorGenerationJob]] = kwargs.pop("cls", None) - :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/merge-patch+json". - :paramtype content_type: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails - :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 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 prepare_request(_continuation_token=None): - :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/merge-patch+json". - :paramtype content_type: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + _request = build_beta_evaluators_list_generation_jobs_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.EvaluatorGenerationJob], + 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 patch_agent_details( - self, - agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - agent_endpoint: Optional[_models.AgentEndpoint] = None, - agent_card: Optional[_models.AgentCard] = None, - **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: + """Cancels an evaluator generation job. - :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.AgentEndpoint - :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 + Cancels an evaluator generation job by its ID. + + :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 :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5278,27 +10282,14 @@ def patch_agent_details( } 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.AgentDetails] = 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 - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - _request = build_beta_agents_patch_agent_details_request( - agent_name=agent_name, - content_type=content_type, + _request = build_beta_evaluators_cancel_generation_job_request( + job_id=job_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -5331,127 +10322,24 @@ def patch_agent_details( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentDetails, response.json()) + deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def create_session( - self, - agent_name: str, - *, - isolation_key: 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 isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: 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, *, isolation_key: str, 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 isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str - :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], - *, - isolation_key: str, - 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 isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str - :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 create_session( - self, - agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - isolation_key: str, - 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. + def delete_generation_job( # pylint: disable=inconsistent-return-statements + 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. - :param agent_name: The name of the agent to create a session for. 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 isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str - :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 + :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 = { @@ -5462,30 +10350,14 @@ def create_session( } 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.AgentSessionResource] = 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 = {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_agents_create_session_request( - agent_name=agent_name, - isolation_key=isolation_key, - content_type=content_type, + _request = build_beta_evaluators_delete_generation_job_request( + job_id=job_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -5494,20 +10366,14 @@ def create_session( } _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 [201]: - 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, @@ -5515,26 +10381,83 @@ def create_session( ) raise HttpResponseError(response=response, model=error) - 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 cls(pipeline_response, None, {}) # type: ignore - return deserialized # 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. + + :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 + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + 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 + :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 + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def generate(self, insight: IO[bytes], *, 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: 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 + :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 generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: + """Generate Insights. - :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: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :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 = { @@ -5545,15 +10468,23 @@ def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _model } 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.AgentSessionResource] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Insight] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_request( - agent_name=agent_name, - session_id=session_id, + content_type = content_type or "application/json" + _content = None + if isinstance(insight, (IOBase, bytes)): + _content = insight + else: + _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_insights_generate_request( + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -5570,7 +10501,7 @@ def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _model 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 @@ -5586,7 +10517,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.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -5594,21 +10525,16 @@ 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, *, isolation_key: str, **kwargs: Any - ) -> None: - """Deletes a session synchronously. Returns 204 No Content when the session is deleted or does not - exist. + def get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any) -> _models.Insight: + """Get a specific insight by Id. - :param agent_name: The name of the agent. Required. - :type agent_name: str - :param session_id: The session identifier. Required. - :type session_id: str - :keyword isolation_key: Isolation key used by the agent endpoint to enforce session ownership - for session-mutating operations. Required. - :paramtype isolation_key: str - :return: None - :rtype: None + :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 = { @@ -5622,12 +10548,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[_models.Insight] = kwargs.pop("cls", None) - _request = build_beta_agents_delete_session_request( - agent_name=agent_name, - session_id=session_id, - isolation_key=isolation_key, + _request = build_beta_insights_get_request( + insight_id=insight_id, + include_coordinates=include_coordinates, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5637,14 +10562,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", 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, @@ -5652,45 +10583,49 @@ def delete_session( # pylint: disable=inconsistent-return-statements ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.Insight, 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_sessions( + def list( self, - agent_name: str, *, - 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.AgentSessionResource"]: - """Returns a list of sessions for the specified agent. + ) -> ItemPaged["_models.Insight"]: + """List all insights in reverse chronological order (newest first). - :param agent_name: The name of the agent. 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] + :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.AgentSessionResource]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -5700,36 +10635,63 @@ def list_sessions( } 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_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", []), + 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 @@ -5749,126 +10711,112 @@ def get_next(_continuation_token=None): 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) - _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, - ) - 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) +class BetaMemoryStoresOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - _decompress = kwargs.pop("decompress", True) - _stream = True - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`memory_stores` attribute. + """ - response = pipeline_response.http_response + 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") - 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) + @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. - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + :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 + :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: + """ - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SessionLogEvent, response.text()) + @overload + def create( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + :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: + """ - return deserialized # type: ignore + @overload + def create( + self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. + + :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 _upload_session_file( - self, agent_name: str, agent_session_id: str, content: bytes, *, path: str, **kwargs: Any - ) -> _models.SessionFileWriteResponse: - """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( + 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 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: SessionFileWriteResponse. The SessionFileWriteResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.SessionFileWriteResponse + :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 :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5882,15 +10830,24 @@ 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.SessionFileWriteResponse] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - _content = content + 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 + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_upload_session_file_request( - agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, + _request = build_beta_memory_stores_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -5910,7 +10867,7 @@ def _upload_session_file( 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 @@ -5926,100 +10883,99 @@ def _upload_session_file( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SessionFileWriteResponse, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore 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. + @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. - :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 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 :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[Iterator[bytes]] = kwargs.pop("cls", None) - - _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, - ) - 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", 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 [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) + @overload + def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + :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: + """ - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + @overload + def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. - return deserialized # type: ignore + :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 get_session_files( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any - ) -> _models.SessionDirectoryListResponse: - """List files and directories at a given path in the session sandbox. Returns only the immediate - children of the specified directory (non-recursive). + 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 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: SessionDirectoryListResponse. The SessionDirectoryListResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.SessionDirectoryListResponse + :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 = { @@ -6030,16 +10986,27 @@ def get_session_files( } 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.SessionDirectoryListResponse] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_files_request( - agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, + 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, ) @@ -6072,7 +11039,7 @@ def get_session_files( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SessionDirectoryListResponse, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6080,97 +11047,13 @@ def get_session_files( return deserialized # 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. - - :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 = 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.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 get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: - """Get an evaluation run by name. + 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 - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6184,9 +11067,9 @@ 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.MemoryStoreDetails] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_get_request( + _request = build_beta_memory_stores_get_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -6212,12 +11095,16 @@ 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) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6226,22 +11113,37 @@ def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: @distributed_trace def list( - self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.EvaluationTaxonomy"]: - """List evaluation taxonomies. + 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 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] + :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.EvaluationTaxonomy]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.MemoryStoreDetails]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -6251,60 +11153,35 @@ def list( } 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) + 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.EvaluationTaxonomy], - deserialized.get("value", []), + List[_models.MemoryStoreDetails], + 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 @@ -6314,20 +11191,24 @@ 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) @distributed_trace - def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete an evaluation taxonomy by name. + 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 - :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 = { @@ -6341,128 +11222,11 @@ 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) - - _request = build_beta_evaluation_taxonomies_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) - - _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 create( - self, name: str, body: _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 body: The evaluation taxonomy. Required. - :type body: ~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, body: JSON, *, 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 body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create( - self, name: str, body: IO[bytes], *, 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 body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @distributed_trace - def create( - self, name: str, body: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. - - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param body: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, JSON, - IO[bytes] Required. - :type body: ~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 = { - 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.EvaluationTaxonomy] = 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.DeleteMemoryStoreResult] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_create_request( + _request = build_beta_memory_stores_delete_request( name=name, - content_type=content_type, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -6479,19 +11243,23 @@ 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.DeleteMemoryStoreResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6499,72 +11267,56 @@ def create( return deserialized # type: ignore @overload - def update( - self, name: str, body: _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 body: The evaluation taxonomy. Required. - :type body: ~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: - """ - + 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 update( + def _search_memories( self, name: str, body: 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 body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - + ) -> _models.MemoryStoreSearchResult: ... @overload - def update( + def _search_memories( self, name: str, body: 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 body: The evaluation taxonomy. 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: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + ) -> _models.MemoryStoreSearchResult: ... @distributed_trace - def update( - self, name: str, body: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + 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 evaluation taxonomy. Required. + :param name: The name of the memory store to search. Required. :type name: str - :param body: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, JSON, - IO[bytes] Required. - :type body: ~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 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 = { @@ -6579,8 +11331,18 @@ def update( _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.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)): @@ -6588,7 +11350,7 @@ def update( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluation_taxonomies_update_request( + _request = build_beta_memory_stores_search_memories_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -6616,65 +11378,33 @@ 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.MemoryStoreSearchResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore 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( + def _update_memories_initial( self, name: str, + body: Union[JSON, IO[bytes]] = _Unset, *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, **kwargs: Any - ) -> ItemPaged["_models.EvaluatorVersion"]: - """List all versions of the given evaluator. - - :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 {} - - cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) - + ) -> Iterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -6683,257 +11413,265 @@ 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) - - 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 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. - - :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 {} + _headers = case_insensitive_dict(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 {}) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - def prepare_request(next_link=None): - if not next_link: + 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_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) + _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) - 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 = True + 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.EvaluatorVersion], - deserialized.get("value", []), + 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, ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + raise HttpResponseError(response=response, model=error) - def get_next(next_link=None): - _request = prepare_request(next_link) + response_headers = {} + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + deserialized = response.iter_bytes() if _decompress else response.iter_raw() - 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) + @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 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. + 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 resource. Required. + :param name: The name of the memory store to update. 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 + :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 = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) + 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 - _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 + 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 ) - response = pipeline_response.http_response + @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. - 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) + :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 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 + :raises ~azure.core.exceptions.HttpResponseError: + """ - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) + @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. - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + :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 + :raises ~azure.core.exceptions.HttpResponseError: + """ - return deserialized # type: ignore + @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. + + :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 + :raises ~azure.core.exceptions.HttpResponseError: + """ @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. + 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: The name of the resource. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: The version of the EvaluatorVersion to delete. Required. - :type version: str - :return: None - :rtype: None + :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 = { @@ -6944,15 +11682,29 @@ def delete_version( # pylint: disable=inconsistent-return-statements } 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.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)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluators_delete_version_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, headers=_headers, params=_params, ) @@ -6961,92 +11713,131 @@ 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) - 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.MemoryStoreDeleteScopeResult, 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_version( + def create_memory( self, name: str, - evaluator_version: _models.EvaluatorVersion, *, + scope: str, + content: str, + kind: Union[str, _models.MemoryItemKind], content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + ) -> _models.MemoryItem: + """Create a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. + Required. + :paramtype scope: str + :keyword content: The content of the memory. Required. + :paramtype content: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Required. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind :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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :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_memory( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Create a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: JSON + :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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :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_memory( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Create a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: IO[bytes] + :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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :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_memory( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + content: str = _Unset, + kind: Union[str, _models.MemoryItemKind] = _Unset, + **kwargs: Any + ) -> _models.MemoryItem: + """Create a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. Required. :type name: str - :param evaluator_version: Is one of the following types: EvaluatorVersion, JSON, IO[bytes] + :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 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 + :paramtype scope: str + :keyword content: The content of the memory. Required. + :paramtype content: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Required. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7061,16 +11852,25 @@ 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.MemoryItem] = kwargs.pop("cls", None) + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + if content is _Unset: + raise TypeError("missing required argument: content") + if kind is _Unset: + raise TypeError("missing required argument: kind") + body = {"content": content, "kind": kind, "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(evaluator_version, (IOBase, bytes)): - _content = evaluator_version + if isinstance(body, (IOBase, bytes)): + _content = body else: - _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluators_create_version_request( + _request = build_beta_memory_stores_create_memory_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -7091,19 +11891,23 @@ def create_version( 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) - 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.EvaluatorVersion, response.json()) + deserialized = _deserialize(_models.MemoryItem, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -7111,96 +11915,164 @@ 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_memory( + self, name: str, memory_id: str, *, content: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. 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 memory_id: The ID of the memory item to update. Required. + :type memory_id: str + :keyword content: The updated content of the memory. Required. + :paramtype content: str :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: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :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_memory( + self, name: str, memory_id: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. 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 memory_id: The ID of the memory item to update. Required. + :type memory_id: 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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :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_memory( + self, name: str, memory_id: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. 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 memory_id: The ID of the memory item to update. Required. + :type memory_id: 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: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :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_memory( + self, name: str, memory_id: str, body: Union[JSON, IO[bytes]] = _Unset, *, content: str = _Unset, **kwargs: Any + ) -> _models.MemoryItem: + """Update a memory item in a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store. 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 + :param memory_id: The ID of the memory item to update. Required. + :type memory_id: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword content: The updated content of the memory. Required. + :paramtype content: str + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem + :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.MemoryItem] = kwargs.pop("cls", None) + + if body is _Unset: + if content is _Unset: + raise TypeError("missing required argument: content") + body = {"content": content} + 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_memory_request( + name=name, + memory_id=memory_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 _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.MemoryItem, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get_memory(self, name: str, memory_id: str, **kwargs: Any) -> _models.MemoryItem: + """Retrieve a memory item from a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to retrieve. Required. + :type memory_id: str + :return: MemoryItem. The MemoryItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7211,25 +12083,15 @@ def update_version( } 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.EvaluatorVersion] = kwargs.pop("cls", None) - - 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 + cls: ClsType[_models.MemoryItem] = kwargs.pop("cls", None) - _request = build_beta_evaluators_update_version_request( + _request = build_beta_memory_stores_get_memory_request( name=name, - version=version, - content_type=content_type, + memory_id=memory_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -7253,92 +12115,288 @@ def update_version( 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.EvaluatorVersion, response.json()) + deserialized = _deserialize(_models.MemoryItem, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # 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 list_memories( + self, + name: str, + *, + scope: str, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> ItemPaged["_models.MemoryItem"]: + """List all memory items in a memory store. - :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 memory store. Required. + :type name: str + :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. + Required. + :paramtype scope: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 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: An iterator like instance of MemoryItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.MemoryItem] :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def generate(self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.Insight: - """Generate Insights. + def list_memories( + self, + name: str, + body: JSON, + *, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> ItemPaged["_models.MemoryItem"]: + """List all memory items in a memory store. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: JSON + :param name: The name of the memory store. Required. + :type name: str + :param body: Required. + :type body: JSON + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 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: An iterator like instance of MemoryItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.MemoryItem] :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def generate(self, insight: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.Insight: - """Generate Insights. + def list_memories( + self, + name: str, + body: IO[bytes], + *, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> ItemPaged["_models.MemoryItem"]: + """List all memory items in a memory store. + + :param name: The name of the memory store. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: An iterator like instance of MemoryItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.MemoryItem] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def list_memories( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + kind: Optional[Union[str, _models.MemoryItemKind]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.MemoryItem"]: + """List all memory items in 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, such as a user ID. + Required. + :paramtype scope: str + :keyword kind: The kind of the memory item. Known values are: "user_profile", "chat_summary", + and "procedural". Default value is None. + :paramtype kind: str or ~azure.ai.projects.models.MemoryItemKind + :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 MemoryItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.MemoryItem] + :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[List[_models.MemoryItem]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + # BUG? These lines were inside the prepare_request() method. Moved here instead. + 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)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + def prepare_request(_continuation_token=None): + + _request = build_beta_memory_stores_list_memories_request( + name=name, + kind=kind, + limit=limit, + order=order, + after=_continuation_token, + before=before, + 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) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.MemoryItem], + 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) - :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: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight - :raises ~azure.core.exceptions.HttpResponseError: - """ + return pipeline_response + + return ItemPaged(get_next, extract_data) @distributed_trace - def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: - """Generate Insights. + def delete_memory(self, name: str, memory_id: str, **kwargs: Any) -> _models.DeleteMemoryResult: + """Delete a memory item from a memory store. - :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 memory store. Required. + :type name: str + :param memory_id: The ID of the memory item to delete. Required. + :type memory_id: str + :return: DeleteMemoryResult. The DeleteMemoryResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteMemoryResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7349,23 +12407,15 @@ def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: A } 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.Insight] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(insight, (IOBase, bytes)): - _content = insight - else: - _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.DeleteMemoryResult] = kwargs.pop("cls", None) - _request = build_beta_insights_generate_request( - content_type=content_type, + _request = build_beta_memory_stores_delete_memory_request( + name=name, + memory_id=memory_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -7382,7 +12432,7 @@ def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: A 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 @@ -7398,26 +12448,46 @@ def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: A if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Insight, response.json()) + deserialized = _deserialize(_models.DeleteMemoryResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +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 get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any) -> _models.Insight: - """Get a specific insight by Id. + def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: + """List all versions of the given ModelVersion. - :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 + :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, @@ -7426,87 +12496,86 @@ def get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, ** } 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.Insight] = 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_insights_get_request( - insight_id=insight_id, - 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) - _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) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + 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 ) - raise HttpResponseError(response=response, model=error) + response = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.Insight, 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, {}) # type: ignore + return pipeline_response - return deserialized # type: ignore + return ItemPaged(get_next, extract_data) @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). + def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: + """List the latest version of each ModelVersion. - :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] + :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.Insight]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -7519,12 +12588,7 @@ def list( 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, + _request = build_beta_models_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -7559,145 +12623,243 @@ def prepare_request(next_link=None): } _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request + 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 - 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) + 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.ModelVersion, 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) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + return deserialized # type: ignore - return pipeline_response + @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. - return ItemPaged(get_next, extract_data) + :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) -class BetaMemoryStoresOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + _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) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`memory_stores` attribute. - """ + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - 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") + 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 create( + def update( self, - *, name: str, - definition: _models.MemoryStoreDefinition, - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, + version: str, + body: _models.UpdateModelVersionRequest, + *, + content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. - :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 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/json". + Default value is "application/merge-patch+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: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :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 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 body: Required. + :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/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :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 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 body: Required. + :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/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :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 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 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 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 = { @@ -7712,23 +12874,18 @@ 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.ModelVersion] = 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_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_memory_stores_create_request( + _request = build_beta_models_update_request( + name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7748,23 +12905,19 @@ def create( 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.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.ModelVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -7772,91 +12925,96 @@ def create( return deserialized # type: ignore @overload - def update( + def pending_create_version( self, name: str, + version: str, + model_version: _models.ModelVersion, *, content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. - :param name: The name of the memory store to update. Required. + :param name: Name of the model. Required. :type name: str + :param version: Version of the model. Required. + :type version: str + :param model_version: Model version to create. Required. + :type model_version: ~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 + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + def pending_create_version( + self, name: str, version: str, model_version: 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: The name of the memory store to update. Required. + :param name: Name of the model. Required. :type name: str - :param body: Required. - :type body: JSON + :param version: Version of the model. Required. + :type version: str + :param model_version: Model version to create. Required. + :type model_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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + def pending_create_version( + self, + name: str, + version: str, + model_version: 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: The name of the memory store to update. Required. - :type name: str - :param body: Required. - :type body: IO[bytes] + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param model_version: Model version to create. Required. + :type model_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: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse :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. + def pending_create_version( + self, name: str, version: str, model_version: 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 name: The name of the memory store to update. Required. + :param name: Name of the model. 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 + :param version: Version of the model. Required. + :type version: str + :param model_version: Model version to create. Is one of the following types: ModelVersion, + JSON, IO[bytes] Required. + :type model_version: ~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 = { @@ -7871,20 +13029,18 @@ def update( _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.CreateAsyncResponse] = 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 + if isinstance(model_version, (IOBase, bytes)): + _content = model_version else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(model_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_update_request( + _request = build_beta_models_pending_create_version_request( name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7904,37 +13060,130 @@ def update( 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 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) + + 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.MemoryStoreDetails, 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 + @overload + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: _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 pending_upload_request: Required. + :type pending_upload_request: ~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, + pending_upload_request: 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 pending_upload_request: Required. + :type pending_upload_request: 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, + pending_upload_request: 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 pending_upload_request: Required. + :type pending_upload_request: 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 get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: - """Retrieve a memory store. + def pending_upload( + self, + name: str, + version: str, + pending_upload_request: Union[_models.ModelPendingUploadRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. - :param name: The name of the memory store to retrieve. Required. + :param name: Name of the model. Required. :type name: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :param version: Version of the model. Required. + :type version: str + :param pending_upload_request: Is one of the following types: ModelPendingUploadRequest, JSON, + IO[bytes] Required. + :type pending_upload_request: ~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 = { @@ -7945,14 +13194,25 @@ def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: } 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.MemoryStoreDetails] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelPendingUploadResponse] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_get_request( + content_type = content_type or "application/json" + _content = None + if isinstance(pending_upload_request, (IOBase, bytes)): + _content = pending_upload_request + else: + _content = json.dumps(pending_upload_request, 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, ) @@ -7976,120 +13236,115 @@ def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: 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.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.ModelPendingUploadResponse, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( + @overload + def get_credentials( self, + name: str, + version: str, + credential_request: _models.ModelCredentialRequest, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + content_type: str = "application/json", **kwargs: Any - ) -> ItemPaged["_models.MemoryStoreDetails"]: - """List all memory stores. + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :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] + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param credential_request: Required. + :type credential_request: ~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: """ - _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 + @overload + def get_credentials( + self, + name: str, + version: str, + credential_request: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - 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) + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param credential_request: Required. + :type credential_request: 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: + """ - return pipeline_response + @overload + def get_credentials( + self, + name: str, + version: str, + credential_request: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - return ItemPaged(get_next, extract_data) + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param credential_request: Required. + :type credential_request: 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 delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: - """Delete a memory store. + def get_credentials( + self, + name: str, + version: str, + credential_request: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param name: The name of the memory store to delete. Required. + :param name: Name of the model. Required. :type name: str - :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult + :param version: Version of the model. Required. + :type version: str + :param credential_request: Is one of the following types: ModelCredentialRequest, JSON, + IO[bytes] Required. + :type credential_request: ~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 = { @@ -8100,14 +13355,25 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: } 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.DeleteMemoryStoreResult] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_delete_request( + content_type = content_type or "application/json" + _content = None + if isinstance(credential_request, (IOBase, bytes)): + _content = credential_request + else: + _content = json.dumps(credential_request, 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, ) @@ -8131,73 +13397,44 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: 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.DeleteMemoryStoreResult, response.json()) + deserialized = _deserialize(_models.DatasetCredential, 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: ... + +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 _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. + def get(self, name: str, **kwargs: Any) -> _models.RedTeam: + """Get a redteam by name. - :param name: The name of the memory store to search. Required. + :param name: Identifier of the red team run. 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 + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8208,34 +13445,14 @@ def _search_memories( } 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.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 + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_search_memories_request( + _request = build_beta_red_teams_get_request( name=name, - content_type=content_type, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -8259,33 +13476,161 @@ def _search_memories( 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) + + 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) -> 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.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, + 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.RedTeam], + 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) + + 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( + 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. - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.MemoryStoreSearchResult, response.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: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + @overload + def create(self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - return deserialized # type: ignore + :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: + """ - 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]: + @distributed_trace + 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, @@ -8298,27 +13643,16 @@ def _update_memories_initial( _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) + cls: ClsType[_models.RedTeam] = 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 + 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_memory_stores_update_memories_request( - name=name, + _request = build_beta_red_teams_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8331,18 +13665,19 @@ def _update_memories_initial( _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 ) 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 + 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, @@ -8350,209 +13685,132 @@ def _update_memories_initial( ) 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 _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, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # 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 BetaRoutinesOperations: + """ + .. 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:`routines` 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. - - :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 + 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 - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :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 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_or_update( + self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Routine: + """Create or update a routine. - :param name: The name of the memory store. Required. - :type name: str + :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: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :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_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: The name of the memory store. Required. - :type name: str + :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: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :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_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: The name of the memory store. Required. - :type name: str + :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 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 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 = { @@ -8567,12 +13825,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.Routine] = kwargs.pop("cls", None) if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = {"scope": scope} + 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 @@ -8581,8 +13841,8 @@ 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_routines_create_or_update_request( + routine_name=routine_name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8600,57 +13860,324 @@ def delete_scope( _request, stream=_stream, **kwargs ) - response = pipeline_response.http_response + 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.Routine, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Retrieve a routine. + + :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 = { + 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.Routine] = kwargs.pop("cls", None) + + _request = build_beta_routines_get_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) + + _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.Routine, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def enable(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Enable a routine. + + :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 = { + 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.Routine] = kwargs.pop("cls", None) + + _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) + + _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.Routine, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Disable a routine. + + :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 = { + 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.Routine] = kwargs.pop("cls", None) + + _request = build_beta_routines_disable_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) + + _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.Routine, 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.Routine"]: + """List routines. + + :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.Routine]] = 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): - 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, + _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, ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.MemoryStoreDeleteScopeResult, response.json()) + 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 - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + 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) - return deserialized # type: ignore + 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 -class BetaRedTeamsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + 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) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`red_teams` attribute. - """ + return pipeline_response - 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 ItemPaged(get_next, extract_data) @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.RedTeam: - """Get a redteam by name. + def delete(self, routine_name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete 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: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8664,10 +14191,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[None] = kwargs.pop("cls", None) - _request = build_beta_red_teams_get_request( - name=name, + _request = build_beta_routines_delete_request( + routine_name=routine_name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -8677,45 +14204,64 @@ def get(self, name: str, **kwargs: Any) -> _models.RedTeam: } _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) - raise HttpResponseError(response=response) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.RedTeam, response.json()) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + 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 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] + 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.RedTeam]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.RoutineRun]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -8725,58 +14271,37 @@ 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_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.RedTeam], - deserialized.get("value", []), + List[_models.RoutineRun], + 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 @@ -8786,65 +14311,96 @@ 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. + def dispatch( + self, + routine_name: str, + *, + content_type: str = "application/json", + payload: Optional[_models.RoutineDispatchPayload] = None, + **kwargs: Any + ) -> _models.DispatchRoutineResult: + """Queue an asynchronous routine dispatch. - :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 :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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult :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( + self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DispatchRoutineResult: + """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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult :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( + self, routine_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DispatchRoutineResult: + """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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult :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( + self, + routine_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + payload: Optional[_models.RoutineDispatchPayload] = None, + **kwargs: Any + ) -> _models.DispatchRoutineResult: + """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: DispatchRoutineResult. The DispatchRoutineResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8859,16 +14415,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.DispatchRoutineResult] = 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_request( + routine_name=routine_name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8888,7 +14448,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 @@ -8904,7 +14464,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.DispatchRoutineResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -9852,47 +15412,311 @@ def prepare_request(_continuation_token=None): _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 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 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 = { + 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.ToolboxVersionObject] = kwargs.pop("cls", None) + + _request = build_beta_toolboxes_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) + 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.ToolboxVersionObject, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @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. + + :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 + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject + :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. + + :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 + :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. + + :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 + :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. + + :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 + :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.ToolboxObject] = 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} + 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_toolboxes_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.ToolboxObject, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + 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. + + :param name: The name of the toolbox to delete. Required. + :type 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 {} - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + cls: ClsType[None] = kwargs.pop("cls", None) - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + _request = build_beta_toolboxes_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) - 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) + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - return pipeline_response + response = pipeline_response.http_response - return ItemPaged(get_next, extract_data) + 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 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 = { @@ -9906,9 +15730,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, @@ -9920,20 +15744,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, @@ -9941,86 +15759,200 @@ 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 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 + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create(self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: + """Creates a skill. + + :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 + :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. + + :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) - :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 - :raises ~azure.core.exceptions.HttpResponseError: - """ + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) - @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. + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - :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 - :raises ~azure.core.exceptions.HttpResponseError: - """ + return deserialized # type: ignore @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_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: + """Creates a skill from a zip package. - :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 + :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 = { @@ -10034,23 +15966,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)) - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", 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: - 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 - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = content - _request = build_beta_toolboxes_update_request( - name=name, + _request = build_beta_skills_create_from_package_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10070,7 +15991,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 @@ -10086,7 +16007,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 @@ -10094,13 +16015,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.SkillDetails: + """Retrieves a skill. - :param name: The name of the toolbox to delete. Required. + :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 = { @@ -10114,9 +16035,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, @@ -10127,14 +16048,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, @@ -10142,21 +16069,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 = { @@ -10170,11 +16100,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, @@ -10184,14 +16113,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, @@ -10199,42 +16134,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.SkillObject: - """Creates a skill. + ) -> _models.SkillDetails: + """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 @@ -10250,56 +16264,64 @@ def create( 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillObject: - """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. Default value is "application/json". :paramtype content_type: str - :return: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create(self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillObject: - """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. Default value is "application/json". :paramtype content_type: str - :return: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @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.SkillObject: - """Creates a skill. + ) -> _models.SkillDetails: + """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 @@ -10312,8 +16334,8 @@ def create( 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10328,12 +16350,10 @@ def create( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillObject] = kwargs.pop("cls", 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 = {"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 @@ -10342,76 +16362,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.SkillObject, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def create_from_package(self, body: bytes, **kwargs: Any) -> _models.SkillObject: - """Creates a skill from a zip package. - - :param body: The zip package used to create the skill. Required. - :type body: bytes - :return: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject - :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.SkillObject] = kwargs.pop("cls", None) - - _content = body - - _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, @@ -10431,7 +16383,7 @@ def create_from_package(self, body: bytes, **kwargs: Any) -> _models.SkillObject 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 @@ -10447,7 +16399,7 @@ def create_from_package(self, body: bytes, **kwargs: Any) -> _models.SkillObject if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillObject, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -10455,13 +16407,13 @@ def create_from_package(self, body: bytes, **kwargs: Any) -> _models.SkillObject return deserialized # type: ignore @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.SkillObject: - """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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10475,9 +16427,9 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillObject: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillObject] = 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, @@ -10512,21 +16464,41 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillObject: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillObject, 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 = { @@ -10540,10 +16512,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, @@ -10554,7 +16526,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 ) @@ -10575,9 +16547,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 @@ -10585,15 +16560,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.SkillObject"]: - """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 @@ -10609,14 +16588,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 SkillObject - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillObject] + :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.SkillObject]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.DataGenerationJob]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -10628,11 +16612,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, @@ -10646,7 +16632,7 @@ def prepare_request(_continuation_token=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.SkillObject], + List[_models.DataGenerationJob], deserialized.get("data", []), ) if cls: @@ -10675,107 +16661,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.SkillObject: - """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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :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.SkillObject: - """Updates an existing skill. - - :param name: The unique name of the skill. Required. - :type name: str - :param body: Required. - :type body: JSON + 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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :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.SkillObject: - """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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :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.SkillObject: - """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: SkillObject. The SkillObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillObject + :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 = { @@ -10790,20 +16767,17 @@ def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillObject] = 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, @@ -10823,7 +16797,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 @@ -10836,24 +16810,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.SkillObject, 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.DeleteSkillResponse: - """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: DeleteSkillResponse. The DeleteSkillResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillResponse + 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 = { @@ -10867,10 +16847,10 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResponse: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteSkillResponse] = 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, @@ -10904,9 +16884,65 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResponse: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteSkillResponse, 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 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 c7c234ee5494..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 @@ -18,13 +18,16 @@ 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, BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, BetaOperations as GeneratedBetaOperations, BetaRedTeamsOperations, + BetaRoutinesOperations, BetaSchedulesOperations, BetaSkillsOperations, BetaToolboxesOperations, @@ -104,14 +107,20 @@ 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""" + routines: BetaRoutinesOperations + """:class:`~azure.ai.projects.operations.BetaRoutinesOperations` operations""" schedules: BetaSchedulesOperations """:class:`~azure.ai.projects.operations.BetaSchedulesOperations` operations""" toolboxes: BetaToolboxesOperations """: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) @@ -121,6 +130,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 (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( @@ -133,12 +144,15 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: __all__: List[str] = [ "AgentsOperations", "BetaAgentsOperations", + "BetaDatasetsOperations", "BetaEvaluationTaxonomiesOperations", "BetaEvaluatorsOperations", "BetaInsightsOperations", "BetaMemoryStoresOperations", + "BetaModelsOperations", "BetaOperations", "BetaRedTeamsOperations", + "BetaRoutinesOperations", "BetaSchedulesOperations", "BetaSkillsOperations", "BetaToolboxesOperations", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py index 02274e66fac2..a2f129f1dae1 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_agents.py @@ -8,41 +8,17 @@ Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import Union, Optional, Any, IO, overload, Final +from typing import Union, Optional, Any, IO, overload from azure.core.exceptions import HttpResponseError from azure.core.tracing.decorator import distributed_trace from ._operations import AgentsOperations as GeneratedAgentsOperations, JSON, _Unset from .. import models as _models -from ..models._enums import _AgentDefinitionOptInKeys -from ..models._patch import _FOUNDRY_FEATURES_HEADER_NAME, _has_header_case_insensitive - -""" -Example service response payload when the caller is trying to use a feature preview without opt-in flag (service error 403 (Forbidden)): - -"error": { - "code": "preview_feature_required", - "message": "Workflow agents is in preview. This operation requires the following opt-in preview feature(s): WorkflowAgents=V1Preview. Include the 'Foundry-Features: WorkflowAgents=V1Preview' header in your request.", - "param": "Foundry-Features", - "type": "invalid_request_error", - "details": [], - "additionalInfo": { - "request_id": "fdbc95804b7599404973026cd9ec732a" - } - } - -""" -_PREVIEW_FEATURE_REQUIRED_CODE: Final = "preview_feature_required" -_PREVIEW_FEATURE_ADDED_ERROR_MESSAGE: Final = ( - '\n**Python SDK users**: This operation requires you to set "allow_preview=True" ' - "when calling the AIProjectClient constructor. " - "\nNote that preview features are under development and subject to change. They should not be used in production environments." -) -_AGENT_OPERATION_FEATURE_HEADERS: Final[str] = ",".join( - [ - _AgentDefinitionOptInKeys.HOSTED_AGENTS_V1_PREVIEW.value, - _AgentDefinitionOptInKeys.WORKFLOW_AGENTS_V1_PREVIEW.value, - _AgentDefinitionOptInKeys.AGENT_ENDPOINT_V1_PREVIEW.value, - ] +from ..models._patch import ( + _FOUNDRY_FEATURES_HEADER_NAME, + _has_header_case_insensitive, + _AGENT_OPERATION_FEATURE_HEADERS, + _PREVIEW_FEATURE_REQUIRED_CODE, + _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE, ) @@ -65,6 +41,7 @@ def create_version( content_type: str = "application/json", metadata: Optional[dict[str, str]] = None, description: Optional[str] = None, + blueprint_reference: Optional[_models.AgentBlueprintReference] = None, **kwargs: Any, ) -> _models.AgentVersionDetails: """Create a new agent version. @@ -91,6 +68,8 @@ def create_version( :paramtype metadata: dict[str, str] :keyword description: A human-readable description of the agent. Default value is None. :paramtype description: str + :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. + :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping :rtype: ~azure.ai.projects.models.AgentVersionDetails :raises ~azure.core.exceptions.HttpResponseError: @@ -154,6 +133,7 @@ def create_version( definition: _models.AgentDefinition = _Unset, metadata: Optional[dict[str, str]] = None, description: Optional[str] = None, + blueprint_reference: Optional[_models.AgentBlueprintReference] = None, **kwargs: Any, ) -> _models.AgentVersionDetails: """Create a new agent version. @@ -179,6 +159,8 @@ def create_version( :paramtype metadata: dict[str, str] :keyword description: A human-readable description of the agent. Default value is None. :paramtype description: str + :keyword blueprint_reference: The blueprint reference for the agent. Default value is None. + :paramtype blueprint_reference: ~azure.ai.projects.models.AgentBlueprintReference :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping :rtype: ~azure.ai.projects.models.AgentVersionDetails :raises ~azure.core.exceptions.HttpResponseError: @@ -200,9 +182,25 @@ def create_version( definition=definition, metadata=metadata, description=description, + blueprint_reference=blueprint_reference, **kwargs, ) except HttpResponseError as exc: + """ + Example service response payload when the caller is trying to use a feature preview without opt-in flag (service error 403 (Forbidden)): + + "error": { + "code": "preview_feature_required", + "message": "Workflow agents is in preview. This operation requires the following opt-in preview feature(s): WorkflowAgents=V1Preview. Include the 'Foundry-Features: WorkflowAgents=V1Preview' header in your request.", + "param": "Foundry-Features", + "type": "invalid_request_error", + "details": [], + "additionalInfo": { + "request_id": "fdbc95804b7599404973026cd9ec732a" + } + } + + """ if exc.status_code == 403 and not self._config.allow_preview and exc.model is not None: api_error_response = exc.model if hasattr(api_error_response, "error") and api_error_response.error is not None: diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_evaluation_rules.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_evaluation_rules.py index 19dcee1ed6bd..859bea44b87b 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_evaluation_rules.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_evaluation_rules.py @@ -12,10 +12,14 @@ from azure.core.exceptions import HttpResponseError from azure.core.tracing.decorator import distributed_trace from ._operations import EvaluationRulesOperations as GeneratedEvaluationRulesOperations, JSON -from ._patch_agents import _PREVIEW_FEATURE_REQUIRED_CODE, _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE from .. import models as _models from ..models._enums import _FoundryFeaturesOptInKeys -from ..models._patch import _FOUNDRY_FEATURES_HEADER_NAME, _has_header_case_insensitive +from ..models._patch import ( + _FOUNDRY_FEATURES_HEADER_NAME, + _has_header_case_insensitive, + _PREVIEW_FEATURE_REQUIRED_CODE, + _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE, +) class EvaluationRulesOperations(GeneratedEvaluationRulesOperations): 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..4a41ce200d89 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -0,0 +1,370 @@ +# 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, Literal, Optional, Union, overload + +from azure.core.exceptions import ResourceNotFoundError +from azure.core.tracing.decorator import distributed_trace + +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.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. + + :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 = 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") + 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 _resolve_azcopy(azcopy_path: Optional[str] = None) -> str: + """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( + "`azcopy` was not found on PATH. Install AzCopy " + "(https://aka.ms/downloadazcopy) and ensure it is on PATH, or " + "pass `azcopy_path=` explicitly." + ) + return azcopy + + @staticmethod + def _validate_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 ``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. + + :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.") + 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. + + :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(): + 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("[create] running: %s", " ".join(redacted)) + + completed = subprocess.run(cmd, check=False, capture_output=True, text=True) + if completed.stdout: + logger.debug("[create] azcopy stdout:\n%s", completed.stdout) + if 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" + f"stdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" + ) + + @overload + def create( + 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: Literal[True] = True, + polling_timeout: float = 300.0, + polling_interval: float = 2.0, + **kwargs: Any, + ) -> ModelVersion: + ... + + @overload + def create( + 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: Literal[False], + polling_timeout: float = 300.0, + polling_interval: float = 2.0, + **kwargs: Any, + ) -> None: + ... + + @distributed_trace + def create( + 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:`pending_create_version` — 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 ``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. + """ + # --- 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_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( + "[create] step 1/3 pending_upload(name=%r, version=%r)", + name, + version, + ) + pending = self.pending_upload( + name=name, + version=version, + pending_upload_request=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] pending_upload_id=%s blob_uri=%s", + pending_upload_id, + container_blob_uri, + ) + + # --- Step 2: Upload via azcopy --------------------------------------- + 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 ------------------------------------- + model_version_body = ModelVersion( + blob_uri=container_blob_uri, + weight_type=weight_type, + base_model=base_model, + description=description, + tags=tags or {}, + ) + logger.info( + "[create] step 3/3 pending_create_version(name=%r, version=%r)", + name, + version, + ) + self.pending_create_version(name=name, version=version, model_version=model_version_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 pending_create_version." + ) from last_exc + time.sleep(polling_interval) + + +__all__ = ["BetaModelsOperations"] diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_sessions.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_sessions.py index 053bbc8292ed..8d417620e725 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_sessions.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_sessions.py @@ -34,7 +34,7 @@ def upload_session_file( # type: ignore[override] *, path: str, **kwargs: Any, - ) -> _models.SessionFileWriteResponse: + ) -> _models.SessionFileWriteResult: """Upload a file to the session sandbox. Accepts either a ``bytes`` buffer or a local file path (``str``). @@ -52,9 +52,9 @@ def upload_session_file( # type: ignore[override] :keyword path: The destination file path within the sandbox, relative to the session home directory. Required. :paramtype path: str - :return: SessionFileWriteResponse. The SessionFileWriteResponse is compatible with + :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionFileWriteResponse + :rtype: ~azure.ai.projects.models.SessionFileWriteResult :raises ~azure.core.exceptions.HttpResponseError: :raises FileNotFoundError: If *content_or_file_path* is a ``str`` and the file does not exist. """ diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_ai_project_instrumentor.py b/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_ai_project_instrumentor.py index 1a22ca314704..c23a994b795e 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_ai_project_instrumentor.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_ai_project_instrumentor.py @@ -645,7 +645,7 @@ def _add_message_event( # pylint: disable=too-many-branches,too-many-statements attribute_name = GEN_AI_INPUT_MESSAGES # Set the attribute on the span - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): span.add_attribute(attribute_name, message_json) def _get_field(self, obj: Any, field: str) -> Any: @@ -722,7 +722,7 @@ def _add_instructions_event( # Use attributes for instructions tracing # System instructions format: array of content objects without role/parts wrapper message_json = json.dumps(content_array, ensure_ascii=False) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): span.add_attribute(GEN_AI_SYSTEM_MESSAGE, message_json) def _status_to_string(self, status: Any) -> str: @@ -782,7 +782,7 @@ def start_create_agent_span( # pylint: disable=too-many-locals reasoning_summary=reasoning_summary, structured_inputs=(str(structured_inputs) if structured_inputs is not None else None), ) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): span.add_attribute(GEN_AI_OPERATION_NAME, OperationName.CREATE_AGENT.value) if name: span.add_attribute(GEN_AI_AGENT_NAME, name) @@ -842,7 +842,7 @@ def start_create_thread_span( # _tool_resources: Optional["ToolResources"] = None, ) -> "Optional[AbstractSpan]": span = start_span(OperationName.CREATE_THREAD, server_address=server_address, port=port) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): for message in messages or []: self.add_thread_message_event(span, message) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_responses_instrumentor.py b/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_responses_instrumentor.py index 95cb28183b35..fdb3cc456214 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_responses_instrumentor.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_responses_instrumentor.py @@ -523,7 +523,7 @@ def _set_attributes(self, span: "AbstractSpan", *attrs: Tuple[str, Any]) -> None def _set_span_attribute_safe(self, span: "AbstractSpan", key: str, value: Any) -> None: """Safely set a span attribute only if the value is meaningful.""" - if not span or not span.span_instance.is_recording: + if not span or not span.span_instance.is_recording(): return # Only set attribute if value exists and is meaningful @@ -846,7 +846,7 @@ def _add_workflow_action_events( conversation_id: Optional[str] = None, ) -> None: """Add workflow action events to the span for workflow agents.""" - if not span or not span.span_instance.is_recording: + if not span or not span.span_instance.is_recording(): return # Check if response has output items @@ -1149,7 +1149,7 @@ def _add_tool_call_events( # pylint: disable=too-many-branches conversation_id: Optional[str] = None, ) -> None: """Add tool call events to the span from response output.""" - if not span or not span.span_instance.is_recording: + if not span or not span.span_instance.is_recording(): return # Extract function calls and tool calls from response output @@ -1638,7 +1638,7 @@ def start_responses_span( gen_ai_provider=RESPONSES_PROVIDER, ) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): # Set operation name attribute (start_span doesn't set this automatically) self._set_attributes( span, @@ -2614,7 +2614,7 @@ def cleanup(self): # Join all accumulated output content complete_content = "".join(self.accumulated_output) - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): # Add tool call events if we detected any output items (tool calls, etc.) if self.has_output_items: # Create mock response with output items for event generation @@ -2721,7 +2721,7 @@ def __init__( ) # End span with proper status - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): self.span.span_instance.set_status( # pyright: ignore [reportPossiblyUnboundVariable] StatusCode.OK @@ -2764,7 +2764,7 @@ def __next__(self): span_attributes=span_attributes, error_type=str(type(e).__name__), ) - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): self.span.span_instance.set_status( # pyright: ignore [reportPossiblyUnboundVariable] StatusCode.ERROR, @@ -2791,7 +2791,7 @@ def _finalize_span(self): span_attributes=span_attributes, ) - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): # Note: For streaming responses, response metadata like tokens, finish_reasons # are typically not available in individual chunks, so we focus on content. @@ -3092,7 +3092,7 @@ def cleanup(self): # Join all accumulated output content complete_content = "".join(self.accumulated_output) - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): # Add tool call events if we detected any output items (tool calls, etc.) if self.has_output_items: # Create mock response with output items for event generation @@ -3199,7 +3199,7 @@ def __init__( ) # End span with proper status - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): self.span.span_instance.set_status( # pyright: ignore [reportPossiblyUnboundVariable] StatusCode.OK @@ -3241,7 +3241,7 @@ async def __anext__(self): span_attributes=span_attributes, error_type=str(type(e).__name__), ) - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): self.span.span_instance.set_status( # pyright: ignore [reportPossiblyUnboundVariable] StatusCode.ERROR, @@ -3268,7 +3268,7 @@ def _finalize_span(self): span_attributes=span_attributes, ) - if self.span.span_instance.is_recording: + if self.span.span_instance.is_recording(): # Note: For streaming responses, response metadata like tokens, finish_reasons # are typically not available in individual chunks, so we focus on content. @@ -3407,7 +3407,7 @@ def start_create_conversation_span( gen_ai_provider=RESPONSES_PROVIDER, ) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): self._set_span_attribute_safe(span, GEN_AI_OPERATION_NAME, OperationName.CREATE_CONVERSATION.value) return span @@ -3605,7 +3605,7 @@ def start_list_conversation_items_span( gen_ai_provider=RESPONSES_PROVIDER, ) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): # Set operation name attribute (start_span doesn't set this automatically) self._set_attributes( span, @@ -3624,7 +3624,7 @@ def _add_conversation_item_event( # pylint: disable=too-many-branches,too-many- item: Any, ) -> None: """Add a conversation item event to the span.""" - if not span or not span.span_instance.is_recording: + if not span or not span.span_instance.is_recording(): return # Extract basic item information diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_utils.py b/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_utils.py index 931c3d2abf7b..47047e2720c3 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_utils.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/telemetry/_utils.py @@ -223,7 +223,7 @@ def start_span( schema_version=GEN_AI_SEMANTIC_CONVENTIONS_SCHEMA_VERSION, ) - if span and span.span_instance.is_recording: + if span and span.span_instance.is_recording(): span.add_attribute(AZ_NAMESPACE, AZ_NAMESPACE_VALUE) span.add_attribute(GEN_AI_PROVIDER_NAME, AGENTS_PROVIDER) diff --git a/sdk/ai/azure-ai-projects/cspell.json b/sdk/ai/azure-ai-projects/cspell.json index b3584c59e861..dd14b6b68b0e 100644 --- a/sdk/ai/azure-ai-projects/cspell.json +++ b/sdk/ai/azure-ai-projects/cspell.json @@ -6,12 +6,15 @@ "aiservices", "ansii", "aread", + "azcopy", + "Azcopy", "azureai", "azureopenai", "balapvbyostoragecanary", "closefd", "cogsvc", "CSDL", + "dargilco", "dedup", "evals", "FineTuning", @@ -27,12 +30,15 @@ "Ministral", "mpkjc", "quantitive", + "recsmplmdl", "reraises", + "simpleqna", + "skoid", "Tadmaq", "Udbk", "UPIA", - "xhigh", - "Vnext" + "Vnext", + "xhigh" ], "ignorePaths": [ "*.csv", diff --git a/sdk/ai/azure-ai-projects/dev_requirements.txt b/sdk/ai/azure-ai-projects/dev_requirements.txt index 3a0781d99156..6641c1e8f14a 100644 --- a/sdk/ai/azure-ai-projects/dev_requirements.txt +++ b/sdk/ai/azure-ai-projects/dev_requirements.txt @@ -8,11 +8,13 @@ azure-core-tracing-opentelemetry azure-mgmt-authorization azure-mgmt-cognitiveservices azure-mgmt-resource +azure-mgmt-subscription azure-monitor-opentelemetry azure-monitor-query jsonref opentelemetry-sdk python-dotenv +black # Can't include those, because they are not supported in Python 3.9. Samples that use these package # cannot be run as pytest, because the pipeline will fail on Python 3.9 jobs. # pillow diff --git a/sdk/ai/azure-ai-projects/docs/subclients.md b/sdk/ai/azure-ai-projects/docs/subclients.md new file mode 100644 index 000000000000..11343e0fbd61 --- /dev/null +++ b/sdk/ai/azure-ai-projects/docs/subclients.md @@ -0,0 +1,194 @@ +# AIProjectClient Subclients + +This document lists all sub-clients available on `AIProjectClient` and their public method counts. Overload methods are not counted. Only synchronous methods are counted (but each one has an equivalent asynchronous method). + +## Summary + +There are a total of 132 unique public methods across all sub-clients. + +### Top-level Sub-clients (stable operations) + +| Subclient | Class Name | Methods Count | +|-----------|------------|----------------| +| `agents` | AgentsOperations | 8 | +| `evaluation_rules` | EvaluationRulesOperations | 4 | +| `connections` | ConnectionsOperations | 3 | +| `datasets` | DatasetsOperations | 9 | +| `deployments` | DeploymentsOperations | 2 | +| `indexes` | IndexesOperations | 5 | +| `telemetry` | TelemetryOperations | 1 | + +### Nested Sub-clients (beta operations) + +| Subclient | Class Name | Methods Count | +|-----------|------------|----------------| +| `beta.agents` | BetaAgentsOperations | 21 | +| `beta.datasets` | BetaDatasetsOperations | 5 | +| `beta.evaluation_taxonomies` | BetaEvaluationTaxonomiesOperations | 5 | +| `beta.evaluators` | BetaEvaluatorsOperations | 13 | +| `beta.insights` | BetaInsightsOperations | 3 | +| `beta.memory_stores` | BetaMemoryStoresOperations | 13 | +| `beta.models` | BetaModelsOperations | 8 | +| `beta.red_teams` | BetaRedTeamsOperations | 3 | +| `beta.routines` | BetaRoutinesOperations | 8 | +| `beta.schedules` | BetaSchedulesOperations | 6 | +| `beta.skills` | BetaSkillsOperations | 7 | +| `beta.toolboxes` | BetaToolboxesOperations | 8 | + + +## Method list table + +Alphabetically sorted, with ".beta" sub-client at the end. + +``` +.agents.create_version +.agents.create_version_from_manifest +.agents.delete +.agents.delete_version +.agents.get +.agents.get_version +.agents.list +.agents.list_versions + +.connections.get +.connections.get_default +.connections.list + +.datasets.create_or_update +.datasets.delete +.datasets.get +.datasets.get_credentials +.datasets.list +.datasets.list_versions +.datasets.pending_upload +.datasets.upload_file +.datasets.upload_folder + +.deployments.get +.deployments.list + +.evaluation_rules.create_or_update +.evaluation_rules.delete +.evaluation_rules.get +.evaluation_rules.list + +.indexes.create_or_update +.indexes.delete +.indexes.get +.indexes.list +.indexes.list_versions + +.telemetry.get_application_insights_connection_string + +.beta.agents.cancel_optimization_job +.beta.agents.create_optimization_job +.beta.agents.create_session +.beta.agents.create_version_from_code +.beta.agents.delete_optimization_job +.beta.agents.delete_session +.beta.agents.delete_session_file +.beta.agents.download_code +.beta.agents.download_session_file +.beta.agents.get_optimization_candidate +.beta.agents.get_optimization_candidate_config +.beta.agents.get_optimization_candidate_results +.beta.agents.get_optimization_job +.beta.agents.get_session +.beta.agents.get_session_files +.beta.agents.get_session_log_stream +.beta.agents.list_optimization_candidates +.beta.agents.list_optimization_jobs +.beta.agents.list_sessions +.beta.agents.patch_agent_details +.beta.agents.upload_session_file + +.beta.datasets.cancel_generation_job +.beta.datasets.create_generation_job +.beta.datasets.delete_generation_job +.beta.datasets.get_generation_job +.beta.datasets.list_generation_jobs + +.beta.evaluation_taxonomies.create +.beta.evaluation_taxonomies.delete +.beta.evaluation_taxonomies.get +.beta.evaluation_taxonomies.list +.beta.evaluation_taxonomies.update + +.beta.evaluators.cancel_generation_job +.beta.evaluators.create_generation_job +.beta.evaluators.create_version +.beta.evaluators.delete_generation_job +.beta.evaluators.delete_version +.beta.evaluators.get_credentials +.beta.evaluators.get_generation_job +.beta.evaluators.get_version +.beta.evaluators.list +.beta.evaluators.list_generation_jobs +.beta.evaluators.list_versions +.beta.evaluators.pending_upload +.beta.evaluators.update_version + +.beta.insights.generate +.beta.insights.get +.beta.insights.list + +.beta.memory_stores.begin_update_memories +.beta.memory_stores.create +.beta.memory_stores.create_memory +.beta.memory_stores.delete +.beta.memory_stores.delete_memory +.beta.memory_stores.delete_scope +.beta.memory_stores.get +.beta.memory_stores.get_memory +.beta.memory_stores.list +.beta.memory_stores.list_memories +.beta.memory_stores.search_memories +.beta.memory_stores.update +.beta.memory_stores.update_memory + +.beta.models.pending_create_version +.beta.models.delete +.beta.models.get +.beta.models.get_credentials +.beta.models.list +.beta.models.list_versions +.beta.models.pending_upload +.beta.models.update + +.beta.red_teams.create +.beta.red_teams.get +.beta.red_teams.list + +.beta.routines.create_or_update +.beta.routines.delete +.beta.routines.disable +.beta.routines.dispatch +.beta.routines.enable +.beta.routines.get +.beta.routines.list +.beta.routines.list_runs + +.beta.schedules.create_or_update +.beta.schedules.delete +.beta.schedules.get +.beta.schedules.get_run +.beta.schedules.list +.beta.schedules.list_runs + +.beta.skills.create +.beta.skills.create_from_package +.beta.skills.delete +.beta.skills.download +.beta.skills.get +.beta.skills.list +.beta.skills.update + +.beta.toolboxes.create_version +.beta.toolboxes.delete +.beta.toolboxes.delete_version +.beta.toolboxes.get +.beta.toolboxes.get_version +.beta.toolboxes.list +.beta.toolboxes.list_versions +.beta.toolboxes.update +``` diff --git a/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd b/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd index ca22422a244f..594848cfb591 100644 --- a/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd +++ b/sdk/ai/azure-ai-projects/post-emitter-fixes.cmd @@ -62,7 +62,17 @@ REM Fix Sphinx docutils warnings in get_session_log_stream docstrings (sync + as REM The emitter wraps bullet/code-block lines with insufficient indentation. powershell -Command "$files='azure\ai\projects\operations\_operations.py','azure\ai\projects\aio\operations\_operations.py'; foreach ($f in $files) { $c=Get-Content $f -Raw; $c=$c -replace 'schema\r?\n\s+is not contractual and may include additional keys or change format\r?\n\s+over time [^\r\n]*clients should treat it as an opaque string\)', 'schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string)'; $c=$c -replace '(message\":\"Starting)\r?\n\s+(FoundryCBAgent server on port 8088\"})', '$1 $2'; $c=$c -replace '(message\":\"INFO: Application)\r?\n\s+(startup complete\.\"})', '$1 $2'; $c=$c -replace '(message\":\"Successfully)\r?\n\s+(connected to container\"})', '$1 $2'; $c=$c -replace '(message\":\"No logs since)\r?\n\s+(last 60 seconds\"})', '$1 $2'; Set-Content $f $c -NoNewline }" +REM Reorder loops in `prepare_multipart_form_data` (azure\ai\projects\_utils\utils.py). +REM The emitter generates the multipart-file loop before the data-field loop, so JSON +REM metadata parts end up after large binary file parts in the encoded body. Some +REM streaming server-side parsers (e.g. the Foundry hosted-agents +REM `create_agent_version_from_code` endpoint) require the small JSON metadata parts +REM to precede the binary file parts; otherwise they report the metadata part as missing. +REM This rewrite swaps the two loops so data fields are appended first. +powershell -Command "$f='azure\ai\projects\_utils\utils.py'; $c=Get-Content $f -Raw; if ($c -notmatch 'Append data fields first') { $pattern='(?s) files: list\[FileType\] = \[\]\r?\n.*? return files'; $new=(@(' files: list[FileType] = []','',' # Append data fields first so they appear before file parts in the encoded',' # multipart body. Some streaming server-side parsers (e.g. the Foundry',' # hosted-agents `create_agent_version_from_code` endpoint) require small',' # JSON metadata parts to precede large binary file parts; otherwise they',' # report the metadata part as missing.',' for data_field in data_fields:',' data_entry = body.get(data_field)',' if data_entry:',' files.append((data_field, str(serialize_multipart_data_entry(data_entry))))','',' for multipart_field in multipart_fields:',' multipart_entry = body.get(multipart_field)',' if isinstance(multipart_entry, list):',' files.extend([(multipart_field, e) for e in multipart_entry])',' elif multipart_entry:',' files.append((multipart_field, multipart_entry))','',' return files') -join [Environment]::NewLine); $c=[regex]::Replace($c, $pattern, $new); Set-Content $f $c -NoNewline }" + REM Finishing by running 'black' tool to format code. +pip install black black --config ../../../eng/black-pyproject.toml . || echo black not found, skipping formatting. diff --git a/sdk/ai/azure-ai-projects/pyrightconfig.json b/sdk/ai/azure-ai-projects/pyrightconfig.json index b8b684eb3af1..c4714f25326c 100644 --- a/sdk/ai/azure-ai-projects/pyrightconfig.json +++ b/sdk/ai/azure-ai-projects/pyrightconfig.json @@ -3,9 +3,13 @@ "reportMissingImports": false, "pythonVersion": "3.11", "extraPaths": [ + "./../../authorization/azure-mgmt-authorization", + "./../../cognitiveservices/azure-mgmt-cognitiveservices", "./../../core/azure-core", "./../../evaluation/azure-ai-evaluation", "./../../identity/azure-identity", + "./../../resources/azure-mgmt-resource", + "./../../resources/azure-mgmt-subscription", "./../../monitor/azure-monitor-opentelemetry" ] } \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/samples/agents/sample_agent_basic.py b/sdk/ai/azure-ai-projects/samples/agents/sample_agent_basic.py index 64b3161d4af6..260902b53c4b 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/sample_agent_basic.py +++ b/sdk/ai/azure-ai-projects/samples/agents/sample_agent_basic.py @@ -42,7 +42,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): - # [START prompt_agent_basic] with project_client.get_openai_client() as openai_client: agent = project_client.agents.create_version( agent_name="MyAgent", @@ -81,4 +80,3 @@ project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) print("Agent deleted") - # [END prompt_agent_basic] diff --git a/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud.py b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud.py new file mode 100644 index 000000000000..4cbb5907ac1c --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud.py @@ -0,0 +1,79 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to perform CRUD operations on External Agents + using the synchronous AIProjectClient. + + External Agents are a preview feature. They register third-party agents hosted + outside Microsoft Foundry. Registration is metadata-only: Foundry uses the + OpenTelemetry agent identifier to light up traces and evaluations for spans + emitted by your external agent. + +USAGE: + python sample_external_agents_crud.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. +""" + +import os + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity import DefaultAzureCredential + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + ExternalAgentDefinition, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, +): + agent_name = "sample-external-agent" + otel_agent_id = "sample-external-agent" + + try: + project_client.agents.delete(agent_name, force=True) + print(f"External agent `{agent_name}` deleted") + except ResourceNotFoundError: + pass + + created = project_client.agents.create_version( + agent_name=agent_name, + definition=ExternalAgentDefinition(otel_agent_id=otel_agent_id), + description="External agent registered by the azure-ai-projects sample.", + metadata={"sample": "external_agents_crud", "status": "created"}, + ) + print(f"Created external agent: {created.name} version={created.version} otel_agent_id={otel_agent_id}") + + fetched_agent = project_client.agents.get(agent_name) + print(f"Retrieved external agent: {fetched_agent.name} latest_version={fetched_agent.versions.latest.version}") + + fetched_version = project_client.agents.get_version(agent_name=agent_name, agent_version=created.version) + print(f"Retrieved external agent version: {fetched_version.name} version={fetched_version.version}") + + external_agents = list(project_client.agents.list(kind="external", limit=10)) + print(f"Found {len(external_agents)} external agents or more") + for external_agent in external_agents: + print(f" - {external_agent.name} ({external_agent.id})") + + deleted = project_client.agents.delete(agent_name, force=True) + print(f"Deleted external agent: {deleted.name} deleted={deleted.deleted}") diff --git a/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud_async.py b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud_async.py new file mode 100644 index 000000000000..f876d077a56d --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/sample_external_agents_crud_async.py @@ -0,0 +1,87 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to perform CRUD operations on External Agents + using the asynchronous AIProjectClient. + + External Agents are a preview feature. They register third-party agents hosted + outside Microsoft Foundry. Registration is metadata-only: Foundry uses the + OpenTelemetry agent identifier to light up traces and evaluations for spans + emitted by your external agent. + +USAGE: + python sample_external_agents_crud_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv aiohttp + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. +""" + +import asyncio +import os + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity.aio import DefaultAzureCredential + +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import ( + ExternalAgentDefinition, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + + +async def main() -> None: + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + agent_name = "sample-external-agent" + otel_agent_id = "sample-external-agent" + + try: + await project_client.agents.delete(agent_name, force=True) + print(f"External agent `{agent_name}` deleted") + except ResourceNotFoundError: + pass + + created = await project_client.agents.create_version( + agent_name=agent_name, + definition=ExternalAgentDefinition(otel_agent_id=otel_agent_id), + description="External agent registered by the azure-ai-projects sample.", + metadata={"sample": "external_agents_crud", "status": "created"}, + ) + print(f"Created external agent: {created.name} version={created.version} otel_agent_id={otel_agent_id}") + + fetched_agent = await project_client.agents.get(agent_name) + print(f"Retrieved external agent: {fetched_agent.name} latest_version={fetched_agent.versions.latest.version}") + + fetched_version = await project_client.agents.get_version(agent_name=agent_name, agent_version=created.version) + print(f"Retrieved external agent version: {fetched_version.name} version={fetched_version.version}") + + external_agents = [] + async for external_agent in project_client.agents.list(kind="external", limit=10): + external_agents.append(external_agent) + print(f"Found {len(external_agents)} external agents or more") + for external_agent in external_agents: + print(f" - {external_agent.name} ({external_agent.id})") + + deleted = await project_client.agents.delete(agent_name, force=True) + print(f"Deleted external agent: {deleted.name} deleted={deleted.deleted}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_azure_monitor_tracing.py b/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_azure_monitor_tracing.py index a9cd0f9907b2..795d5aa7c6dc 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_azure_monitor_tracing.py +++ b/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_azure_monitor_tracing.py @@ -31,11 +31,9 @@ import os from dotenv import load_dotenv -# [START imports_for_azure_monitor_tracing] from opentelemetry import trace from azure.monitor.opentelemetry import configure_azure_monitor -# [END imports_for_azure_monitor_tracing] from azure.identity import DefaultAzureCredential from azure.ai.projects import AIProjectClient from azure.ai.projects.models import PromptAgentDefinition @@ -48,18 +46,14 @@ DefaultAzureCredential() as credential, AIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=credential) as project_client, ): - # [START setup_azure_monitor_tracing] # Enable Azure Monitor tracing application_insights_connection_string = project_client.telemetry.get_application_insights_connection_string() configure_azure_monitor(connection_string=application_insights_connection_string) - # [END setup_azure_monitor_tracing] - # [START create_span_for_scenario] tracer = trace.get_tracer(__name__) scenario = os.path.basename(__file__) with tracer.start_as_current_span(scenario): - # [END create_span_for_scenario] with project_client.get_openai_client() as openai_client: agent_definition = PromptAgentDefinition( model=os.environ["FOUNDRY_MODEL_NAME"], diff --git a/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing.py b/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing.py index 85e1504783d2..8b9be473e7dc 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing.py +++ b/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing.py @@ -31,7 +31,6 @@ from typing import Any from dotenv import load_dotenv -# [START imports_for_console_tracing] from azure.core.settings import settings settings.tracing_implementation = "opentelemetry" @@ -40,7 +39,6 @@ from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter from azure.ai.projects.telemetry import AIProjectInstrumentor -# [END imports_for_console_tracing] from azure.identity import DefaultAzureCredential from azure.ai.projects import AIProjectClient @@ -72,7 +70,6 @@ def display_conversation_item(item: Any) -> None: # pylint: disable=redefined-o print("---") -# [START setup_console_tracing] # Setup tracing to console # Requires opentelemetry-sdk span_exporter = ConsoleSpanExporter() @@ -83,12 +80,9 @@ def display_conversation_item(item: Any) -> None: # pylint: disable=redefined-o # Enable instrumentation with content tracing AIProjectInstrumentor().instrument() -# [END setup_console_tracing] -# [START create_span_for_scenario] scenario = os.path.basename(__file__) with tracer.start_as_current_span(scenario): - # [END create_span_for_scenario] with ( DefaultAzureCredential() as credential, AIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=credential) as project_client, diff --git a/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing_custom_attributes.py b/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing_custom_attributes.py index 44251d2ae830..5bfcea4034e0 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing_custom_attributes.py +++ b/sdk/ai/azure-ai-projects/samples/agents/telemetry/sample_agent_basic_with_console_tracing_custom_attributes.py @@ -50,7 +50,6 @@ # Define the custom span processor that is used for adding the custom # attributes to spans when they are started. -# [START custom_attribute_span_processor] class CustomAttributeSpanProcessor(SpanProcessor): def __init__(self) -> None: pass @@ -68,8 +67,6 @@ def on_end(self, span: ReadableSpan): pass -# [END custom_attribute_span_processor] - # Setup tracing to console # Requires opentelemetry-sdk span_exporter = ConsoleSpanExporter() @@ -82,10 +79,8 @@ def on_end(self, span: ReadableSpan): AIProjectInstrumentor().instrument() # Add the custom span processor to the global tracer provider -# [START add_custom_span_processor_to_tracer_provider] provider = cast(TracerProvider, trace.get_tracer_provider()) provider.add_span_processor(CustomAttributeSpanProcessor()) -# [END add_custom_span_processor_to_tracer_provider] scenario = os.path.basename(__file__) with tracer.start_as_current_span(scenario): diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_ai_search.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_ai_search.py index f2b9f01ee657..e5d6d816ea6e 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_ai_search.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_ai_search.py @@ -49,7 +49,6 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = AzureAISearchTool( azure_ai_search=AzureAISearchToolResource( indexes=[ @@ -61,7 +60,6 @@ ] ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_azure_function.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_azure_function.py index 5e78c32d6325..09c98f891a00 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_azure_function.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_azure_function.py @@ -52,7 +52,6 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = AzureFunctionTool( azure_function=AzureFunctionDefinition( input_binding=AzureFunctionBinding( @@ -77,7 +76,6 @@ ), ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_custom_search.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_custom_search.py index fd3a6a1910b3..0f52fbfa8e47 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_custom_search.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_custom_search.py @@ -58,7 +58,6 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = BingCustomSearchPreviewTool( bing_custom_search_preview=BingCustomSearchToolParameters( search_configurations=[ @@ -69,7 +68,6 @@ ] ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_grounding.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_grounding.py index 386d22dc5e45..735462eb82b0 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_grounding.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_bing_grounding.py @@ -63,7 +63,6 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = BingGroundingTool( bing_grounding=BingGroundingSearchToolParameters( search_configurations=[ @@ -71,7 +70,6 @@ ] ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_browser_automation.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_browser_automation.py index 457e79f40388..54471e71aff4 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_browser_automation.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_browser_automation.py @@ -47,7 +47,6 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = BrowserAutomationPreviewTool( browser_automation_preview=BrowserAutomationToolParameters( connection=BrowserAutomationToolConnectionParameters( @@ -55,7 +54,6 @@ ) ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter.py index 0f053b52a860..d1da6fcd4181 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter.py @@ -39,9 +39,7 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = CodeInterpreterTool() - # [END tool_declaration] # Create agent with code interpreter tool agent = project_client.agents.create_version( @@ -69,11 +67,9 @@ print(f"Response completed (id: {response.id})") # Print code executed by the code interpreter tool. - # [START code_output_extraction] code = next((output.code for output in response.output if output.type == "code_interpreter_call"), "") print("Code Interpreter code:") print(code) - # [END code_output_extraction] # Print final assistant text output. print(f"Agent response: {response.output_text}") diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter_with_files.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter_with_files.py index 68942c42cda8..3421bd5715d9 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter_with_files.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_code_interpreter_with_files.py @@ -40,7 +40,6 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] # Load the CSV file to be processed asset_file_path = os.path.abspath( os.path.join(os.path.dirname(__file__), "../assets/synthetic_500_quarterly_results.csv") @@ -51,7 +50,6 @@ file = openai_client.files.create(purpose="assistants", file=f) tool = CodeInterpreterTool(container=AutoCodeInterpreterToolParam(file_ids=[file.id])) - # [END tool_declaration] print(f"File uploaded (id: {file.id})") diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_computer_use.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_computer_use.py index d77cc7dae39e..59e5af777531 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_computer_use.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_computer_use.py @@ -63,9 +63,7 @@ print("Failed to load required screenshot assets. Please ensure the asset files exist in ../assets/") exit(1) # pylint: disable=consider-using-sys-exit - # [START tool_declaration] tool = ComputerUsePreviewTool(display_width=1026, display_height=769, environment="windows") - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric.py index 3ceb1ee1d28b..587394c4e1aa 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric.py @@ -46,7 +46,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = MicrosoftFabricPreviewTool( fabric_dataagent_preview=FabricDataAgentToolParameters( project_connections=[ @@ -54,7 +53,6 @@ ] ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric_iq.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric_iq.py new file mode 100644 index 000000000000..f43fba64a401 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric_iq.py @@ -0,0 +1,69 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to run a Prompt Agent that uses the + Fabric IQ preview tool with a synchronous client. + +USAGE: + python sample_agent_fabric_iq.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_MODEL_NAME - The deployment name of the AI model, as found under the "Name" column in + the "Models + endpoints" tab in your Microsoft Foundry project. + 3) FABRIC_IQ_PROJECT_CONNECTION_ID - The fully-qualified resource id of the Fabric IQ project connection. + 4) FABRIC_IQ_USER_INPUT - The natural-language question to send to the agent. +""" + +import os +from dotenv import load_dotenv +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import PromptAgentDefinition, FabricIQPreviewTool + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + tool_payload = FabricIQPreviewTool( + project_connection_id=os.environ["FABRIC_IQ_PROJECT_CONNECTION_ID"], + require_approval="never", + ) + + agent = project_client.agents.create_version( + agent_name="MyAgent", + definition=PromptAgentDefinition( + model=os.environ["FOUNDRY_MODEL_NAME"], + instructions="Use the available Fabric IQ tools to answer questions and perform tasks.", + tools=[tool_payload], + ), + ) + print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})") + + user_input = os.environ.get("FABRIC_IQ_USER_INPUT") or input("Enter your question:\n") + + response = openai_client.responses.create( + input=user_input, + extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}}, + ) + + print(f"Agent response: {response.output_text}") + + # Clean up the agent version so unused versions don't accumulate in the project. + project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) + print("Agent deleted") diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric_iq_async.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric_iq_async.py new file mode 100644 index 000000000000..bdd5881cba07 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_fabric_iq_async.py @@ -0,0 +1,76 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to run a Prompt Agent that uses the + Fabric IQ preview tool with an asynchronous client. + +USAGE: + python sample_agent_fabric_iq_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv aiohttp + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_MODEL_NAME - The deployment name of the AI model, as found under the "Name" column in + the "Models + endpoints" tab in your Microsoft Foundry project. + 3) FABRIC_IQ_PROJECT_CONNECTION_ID - The fully-qualified resource id of the Fabric IQ project connection. + 4) FABRIC_IQ_USER_INPUT - The natural-language question to send to the agent. +""" + +import os +import asyncio +from dotenv import load_dotenv +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import PromptAgentDefinition, FabricIQPreviewTool + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + + +async def main(): + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, + ): + tool_payload = FabricIQPreviewTool( + project_connection_id=os.environ["FABRIC_IQ_PROJECT_CONNECTION_ID"], + require_approval="never", + ) + + agent = await project_client.agents.create_version( + agent_name="MyAgent", + definition=PromptAgentDefinition( + model=os.environ["FOUNDRY_MODEL_NAME"], + instructions="Use the available Fabric IQ tools to answer questions and perform tasks.", + tools=[tool_payload], + ), + ) + print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})") + + user_input = os.environ.get("FABRIC_IQ_USER_INPUT") or input("Enter your question:\n") + + response = await openai_client.responses.create( + input=user_input, + extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}}, + ) + + print(f"Agent response: {response.output_text}") + + # Clean up the agent version so unused versions don't accumulate in the project. + await project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) + print("Agent deleted") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_file_search.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_file_search.py index 2a15ce981d7b..e6f64c060be0 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_file_search.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_file_search.py @@ -39,7 +39,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] # Create vector store for file search vector_store = openai_client.vector_stores.create(name="ProductInfoStore") print(f"Vector store created (id: {vector_store.id})") @@ -53,7 +52,6 @@ print(f"File uploaded to vector store (id: {file.id})") tool = FileSearchTool(vector_store_ids=[vector_store.id]) - # [END tool_declaration] # Create agent with file search tool agent = project_client.agents.create_version( diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_function_tool.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_function_tool.py index 7e0ac8e0e56e..991406256f1a 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_function_tool.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_function_tool.py @@ -48,7 +48,6 @@ def get_horoscope(sign: str) -> str: project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = FunctionTool( name="get_horoscope", parameters={ @@ -65,7 +64,6 @@ def get_horoscope(sign: str) -> str: description="Get today's horoscope for an astrological sign.", strict=True, ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_image_generation.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_image_generation.py index 5232a443ca34..b1a4e20fda11 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_image_generation.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_image_generation.py @@ -62,13 +62,11 @@ ): image_generation_model = os.environ["IMAGE_GENERATION_MODEL_DEPLOYMENT_NAME"] - # [START tool_declaration] tool = ImageGenTool( model=image_generation_model, # Model such as "gpt-image-1" quality="low", size="1024x1024", ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", @@ -94,7 +92,6 @@ project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) print("Agent deleted") - # [START download_image] image_data = [output.result for output in response.output if output.type == "image_generation_call"] if image_data and image_data[0]: print("Downloading generated image...") @@ -104,5 +101,4 @@ with open(file_path, "wb") as f: f.write(base64.b64decode(image_data[0])) - # [END download_image] print(f"Image saved to: {file_path}") diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp.py index fb0a553328e9..934a83781e92 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp.py @@ -39,13 +39,11 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] mcp_tool = MCPTool( server_label="api-specs", server_url="https://gitmcp.io/Azure/azure-rest-api-specs", require_approval="always", ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp_with_project_connection.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp_with_project_connection.py index 091db4707b59..3042ac9458db 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp_with_project_connection.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_mcp_with_project_connection.py @@ -42,14 +42,12 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = MCPTool( server_label="api-specs", server_url="https://api.githubcopilot.com/mcp", require_approval="always", project_connection_id=os.environ["MCP_PROJECT_CONNECTION_ID"], ) - # [END tool_declaration] # Create a prompt agent with MCP tool capabilities agent = project_client.agents.create_version( diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_memory_search.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_memory_search.py index 21bce947edc8..433b315b2920 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_memory_search.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_memory_search.py @@ -75,7 +75,6 @@ ) print(f"Created memory store: {memory_store.name} ({memory_store.id}): {memory_store.description}") - # [START memory_search_tool_declaration] # Set scope to associate the memories with # You can also use "{{$userId}}" to take the oid of the request authentication header scope = "user_123" @@ -86,7 +85,6 @@ update_delay=1, # Wait 1 second of inactivity before updating memories # In a real application, set this to a higher value like 300 (5 minutes, default) ) - # [END memory_search_tool_declaration] # Create a prompt agent with memory search tool agent = project_client.agents.create_version( diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi.py index 804c330cd0ce..729971029a6d 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi.py @@ -48,7 +48,6 @@ weather_asset_file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/weather_openapi.json")) - # [START tool_declaration] with open(weather_asset_file_path, "r", encoding="utf-8") as f: openapi_weather = cast(dict[str, Any], jsonref.loads(f.read())) @@ -60,7 +59,6 @@ auth=OpenApiAnonymousAuthDetails(), ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi_with_project_connection.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi_with_project_connection.py index 6c7d88ba4ba4..890b7388608a 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi_with_project_connection.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_openapi_with_project_connection.py @@ -54,7 +54,6 @@ os.path.join(os.path.dirname(__file__), "../assets/tripadvisor_openapi.json") ) - # [START tool_declaration] with open(tripadvisor_asset_file_path, "r", encoding="utf-8") as f: openapi_tripadvisor = cast(dict[str, Any], jsonref.loads(f.read())) @@ -70,7 +69,6 @@ ), ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_sharepoint.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_sharepoint.py index 394e486cc36a..d1c4db82eb1c 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_sharepoint.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_sharepoint.py @@ -46,7 +46,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = SharepointPreviewTool( sharepoint_grounding_preview=SharepointGroundingToolParameters( project_connections=[ @@ -54,7 +53,6 @@ ] ) ) - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_to_agent.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_to_agent.py index 3fe3835b093a..edb7a46fc760 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_to_agent.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_to_agent.py @@ -49,14 +49,12 @@ project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = A2APreviewTool( project_connection_id=os.environ["A2A_PROJECT_CONNECTION_ID"], ) # If the connection is missing target, we need to set the A2A endpoint URL. if os.environ.get("A2A_ENDPOINT"): tool.base_url = os.environ["A2A_ENDPOINT"] - # [END tool_declaration] agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search.py index 3d21a92ae1b6..a08477e27096 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search.py @@ -53,9 +53,7 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = WebSearchTool(user_location=WebSearchApproximateLocation(country="GB", city="London", region="London")) - # [END tool_declaration] # Create Agent with web search tool agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_preview.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_preview.py index cf68ceaf09cf..cdef1789b143 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_preview.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_preview.py @@ -49,9 +49,7 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = WebSearchPreviewTool(user_location=ApproximateLocation(country="GB", city="London", region="London")) - # [END tool_declaration] # Create Agent with web search tool agent = project_client.agents.create_version( agent_name="MyAgent105", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_with_custom_search.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_with_custom_search.py index e4ad578919b5..b66e18e00241 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_with_custom_search.py +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_agent_web_search_with_custom_search.py @@ -58,14 +58,12 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START tool_declaration] tool = WebSearchTool( custom_search_configuration=WebSearchConfiguration( project_connection_id=os.environ["BING_CUSTOM_SEARCH_PROJECT_CONNECTION_ID"], instance_name=os.environ["BING_CUSTOM_SEARCH_INSTANCE_NAME"], ) ) - # [END tool_declaration] # Create Agent with web search tool agent = project_client.agents.create_version( agent_name="MyAgent", diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_toolboxes_with_search_preview.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_toolboxes_with_search_preview.py new file mode 100644 index 000000000000..63bdc57e0ee8 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_toolboxes_with_search_preview.py @@ -0,0 +1,125 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to create a Toolbox in tool-search mode and + invoke it from a Prompt Agent using the synchronous AIProjectClient and + the OpenAI-compatible client. + + A toolbox version that includes 'ToolboxSearchPreviewTool' exposes only + two meta tools at its '/mcp' endpoint -- 'tool_search' and 'call_tool' + -- and defers every other tool behind them. The agent uses an 'MCPTool' + pointed at the toolbox's versioned '/mcp' URL to discover and invoke + those inner tools. + + Toolboxes and tool search are preview features. CRUD goes through + 'project_client.beta.toolboxes'. + +USAGE: + python sample_toolboxes_with_search_preview.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv openai + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_MODEL_NAME - The deployment name of the AI model, as found under the "Name" column in + the "Models + endpoints" tab in your Microsoft Foundry project. + 3) MCP_PROJECT_CONNECTION_ID - The connection resource ID in Custom keys used by + the inner MCP server inside the toolbox. +""" + +import os + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity import DefaultAzureCredential + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + MCPTool, + PromptAgentDefinition, + ToolboxSearchPreviewTool, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + +TOOLBOX_NAME = "toolbox_with_mcp_tool" +INNER_MCP_LABEL = "github" +INNER_MCP_URL = "https://api.githubcopilot.com/mcp" +TOOLBOX_MCP_LABEL = "search-tool" + + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + + inner_mcp_tool = MCPTool( + server_label=INNER_MCP_LABEL, + server_url=INNER_MCP_URL, + require_approval="never", + project_connection_id=os.environ["MCP_PROJECT_CONNECTION_ID"], + ) + + toolbox_version = project_client.beta.toolboxes.create_version( + name=TOOLBOX_NAME, + description=f"Toolbox with `{INNER_MCP_LABEL}` MCP server and tool search enabled.", + tools=[inner_mcp_tool, ToolboxSearchPreviewTool()], + ) + print(f"Created toolbox `{TOOLBOX_NAME}` (version {toolbox_version.version}).") + + toolbox_mcp_url = f"{endpoint}/toolboxes/{TOOLBOX_NAME}/versions/{toolbox_version.version}/mcp?api-version=v1" + token = credential.get_token("https://ai.azure.com/.default").token + + toolbox_mcp_tool = MCPTool( + server_label=TOOLBOX_MCP_LABEL, + server_url=toolbox_mcp_url, + authorization=token, + headers={"Foundry-Features": "Toolboxes=V1Preview"}, + require_approval="never", + ) + + agent = project_client.agents.create_version( + agent_name="MyAgent", + definition=PromptAgentDefinition( + model=os.environ["FOUNDRY_MODEL_NAME"], + instructions=( + "Always use the toolbox search tool to answer questions and perform tasks. " + "Use `tool_search` to discover a relevant tool, then `call_tool` " + "with the tool name returned by the search." + ), + tools=[toolbox_mcp_tool], + ), + ) + print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version}).") + + response = openai_client.responses.create( + input="What is my username in Github profile?", + extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}}, + ) + + for item in response.output: + if item.type == "mcp_approval_request": + print(f"server_label={item.server_label}, name={item.name}") + elif item.type == "mcp_list_tools": + print(f"server_label={item.server_label}, tools={[t.name for t in (item.tools or [])]}") + elif item.type == "mcp_call": + print(f"server_label={item.server_label}, name={item.name}, error={item.error}") + else: + print() + + print(f"Response: {response.output_text}") + + project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) + print(f"Agent version {agent.version} deleted.") diff --git a/sdk/ai/azure-ai-projects/samples/agents/tools/sample_toolboxes_with_search_preview_async.py b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_toolboxes_with_search_preview_async.py new file mode 100644 index 000000000000..bfd43071c2f3 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/tools/sample_toolboxes_with_search_preview_async.py @@ -0,0 +1,130 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates how to create a Toolbox in tool-search mode and + invoke it from a Prompt Agent using the asynchronous AIProjectClient and + the OpenAI-compatible client. + + A toolbox version that includes 'ToolboxSearchPreviewTool' exposes only + two meta tools at its '/mcp' endpoint -- 'tool_search' and 'call_tool' + -- and defers every other tool behind them. The agent uses an 'MCPTool' + pointed at the toolbox's versioned '/mcp' URL to discover and invoke + those inner tools. + + Toolboxes and tool search are preview features. CRUD goes through + 'project_client.beta.toolboxes'. + +USAGE: + python sample_toolboxes_with_search_preview_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv openai aiohttp + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_MODEL_NAME - The deployment name of the AI model, as found under the "Name" column in + the "Models + endpoints" tab in your Microsoft Foundry project. + 3) MCP_PROJECT_CONNECTION_ID - The connection resource ID in Custom keys used by + the inner MCP server inside the toolbox. +""" + +import asyncio +import os + +from dotenv import load_dotenv + +from azure.identity.aio import DefaultAzureCredential + +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import ( + MCPTool, + PromptAgentDefinition, + ToolboxSearchPreviewTool, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + +TOOLBOX_NAME = "toolbox_with_mcp_tool" +INNER_MCP_LABEL = "github" +INNER_MCP_URL = "https://api.githubcopilot.com/mcp" +TOOLBOX_MCP_LABEL = "search-tool" + + +async def main() -> None: + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, + ): + + inner_mcp_tool = MCPTool( + server_label=INNER_MCP_LABEL, + server_url=INNER_MCP_URL, + require_approval="never", + project_connection_id=os.environ["MCP_PROJECT_CONNECTION_ID"], + ) + + toolbox_version = await project_client.beta.toolboxes.create_version( + name=TOOLBOX_NAME, + description=f"Toolbox with `{INNER_MCP_LABEL}` MCP server and tool search enabled.", + tools=[inner_mcp_tool, ToolboxSearchPreviewTool()], + ) + print(f"Created toolbox `{TOOLBOX_NAME}` (version {toolbox_version.version}).") + + toolbox_mcp_url = f"{endpoint}/toolboxes/{TOOLBOX_NAME}/versions/{toolbox_version.version}/mcp?api-version=v1" + token = (await credential.get_token("https://ai.azure.com/.default")).token + + toolbox_mcp_tool = MCPTool( + server_label=TOOLBOX_MCP_LABEL, + server_url=toolbox_mcp_url, + authorization=token, + headers={"Foundry-Features": "Toolboxes=V1Preview"}, + require_approval="never", + ) + + agent = await project_client.agents.create_version( + agent_name="MyAgent", + definition=PromptAgentDefinition( + model=os.environ["FOUNDRY_MODEL_NAME"], + instructions=( + "Always use the toolbox search tool to answer questions and perform tasks. " + "Use `tool_search` to discover a relevant tool, then `call_tool` " + "with the tool name returned by the search." + ), + tools=[toolbox_mcp_tool], + ), + ) + print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version}).") + + response = await openai_client.responses.create( + input="What is my username in Github profile?", + extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}}, + ) + + for item in response.output: + if item.type == "mcp_approval_request": + print(f"server_label={item.server_label}, name={item.name}") + elif item.type == "mcp_list_tools": + print(f"server_label={item.server_label}, tools={[t.name for t in (item.tools or [])]}") + elif item.type == "mcp_call": + print(f"server_label={item.server_label}, name={item.name}, error={item.error}") + else: + print() + + print(f"Response: {response.output_text}") + + await project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) + print(f"Agent version {agent.version} deleted.") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/chat_completions/sample_chat_completions_basic.py b/sdk/ai/azure-ai-projects/samples/chat_completions/sample_chat_completions_basic.py index 78d07ed5540e..845dcd015d58 100644 --- a/sdk/ai/azure-ai-projects/samples/chat_completions/sample_chat_completions_basic.py +++ b/sdk/ai/azure-ai-projects/samples/chat_completions/sample_chat_completions_basic.py @@ -41,7 +41,6 @@ DefaultAzureCredential() as credential, AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): - # [START chat_completions] with project_client.get_openai_client() as openai_client: messages: list[ChatCompletionMessageParam] = [ {"role": "system", "content": "You are a helpful assistant."}, @@ -53,7 +52,6 @@ messages=messages, temperature=0, ) - # [END chat_completions] assistant_message = completion.choices[0].message.content print(f"Assistant: {assistant_message}") diff --git a/sdk/ai/azure-ai-projects/samples/connections/sample_connections.py b/sdk/ai/azure-ai-projects/samples/connections/sample_connections.py index 1de80cfdd689..c9fcbf78bc8c 100644 --- a/sdk/ai/azure-ai-projects/samples/connections/sample_connections.py +++ b/sdk/ai/azure-ai-projects/samples/connections/sample_connections.py @@ -38,7 +38,6 @@ DefaultAzureCredential() as credential, AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): - # [START connections_sample] print("List all connections:") for connection in project_client.connections.list(): print(connection) @@ -66,4 +65,3 @@ print(f"Get the connection named `{connection_name}`, with its credentials:") connection = project_client.connections.get(connection_name, include_credentials=True) print(connection) - # [END connection_sample] diff --git a/sdk/ai/azure-ai-projects/samples/datasets/README.md b/sdk/ai/azure-ai-projects/samples/datasets/README.md new file mode 100644 index 000000000000..68a7e111ff82 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/README.md @@ -0,0 +1,42 @@ +# Azure AI Projects - Dataset Samples + +## Prerequisites + +Before running any sample: + +```bash +pip install "azure-ai-projects>=2.2.0" azure-identity python-dotenv +``` + +To run asynchronous samples, also install `aiohttp`. Samples that produce or consume Azure OpenAI files also require `openai`. + +Set these environment variables: + +| Variable | Required by | Value | +|---|---|---| +| `FOUNDRY_PROJECT_ENDPOINT` | All samples | Your Azure AI Project endpoint, e.g. `https://.services.ai.azure.com/api/projects/` | +| `FOUNDRY_MODEL_NAME` | `simple_qna` data-generation samples | An Azure OpenAI model deployment in your project. For **evaluation** jobs use a [Responses API](https://learn.microsoft.com/azure/foundry/openai/how-to/responses?tabs=python-key#model-support) model; for **fine-tuning** jobs use a chat-completions model (e.g. `gpt-4o`, `gpt-4.1`). | +| `FOUNDRY_AGENT_NAME` | Traces data-generation samples | An agent with recent traces in Application Insights. Foundry Agents and OpenTelemetry-instrumented third-party agents are both supported. | + +Optional per-sample variables (`DATASET_NAME`, `POLL_INTERVAL_SECONDS`, `FOUNDRY_TRACES_WINDOW_DAYS`, etc.) are documented in each sample's docstring. + +## Sample Index + +### Dataset Basics + +| Sample | Description | +|--------|-------------| +| [sample_datasets.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets.py) | Upload files, create, list, and delete versioned Datasets | +| [sample_datasets_async.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets_async.py) | Async version of the dataset CRUD sample | +| [sample_datasets_download.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets_download.py) | Upload a folder as a Dataset and download its files via an Azure storage ContainerClient | + +### Data Generation Jobs + +| Sample | Source(s) | Scenario | Description | +|--------|-----------|----------|-------------| +| [sample_dataset_generation_job_simpleqna_with_prompt_source.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_prompt_source.py) | Prompt | Evaluation | Generate a QnA dataset from an inline prompt and run an evaluation against it end-to-end | +| [sample_dataset_generation_job_simpleqna_with_file_source.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_file_source.py) | File (Azure OpenAI) + Prompt | Evaluation | Generate a QnA dataset from an Azure OpenAI File combined with an inline Prompt | +| [sample_dataset_generation_job_simpleqna_with_agent_source.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_agent_source.py) | Agent definition | Evaluation | Generate a QnA dataset by creating a prompt agent and sourcing the job from the agent's instructions | +| [sample_dataset_generation_job_traces_for_evaluation.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_evaluation.py) | Traces | Evaluation | Generate a QnA dataset from an agent's recent conversation traces | +| [sample_dataset_generation_job_simpleqna_for_finetuning.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_for_finetuning.py) | File (Azure OpenAI) | Supervised fine-tuning | Generate supervised fine-tuning JSONL files (training and validation partitions) from an uploaded Azure OpenAI File | +| [sample_dataset_generation_job_traces_for_finetuning.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_finetuning.py) | Traces | Supervised fine-tuning | Generate supervised fine-tuning JSONL files (training and validation partitions) from an agent's recent conversation traces | diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_for_finetuning.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_for_finetuning.py new file mode 100644 index 000000000000..8a545c3dd6b3 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_for_finetuning.py @@ -0,0 +1,226 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Generates supervised fine-tuning data from a Markdown reference document + uploaded as an Azure OpenAI File. The sample: + + 1. Uploads a short reference document via the Azure OpenAI Files API + (`purpose=user_data`) so it can be referenced by file id. + 2. Creates a `DataGenerationJob` (scenario=SUPERVISED_FINETUNING, + type=simple_qna) that synthesizes short-answer and long-answer + question / answer pairs from the file content and emits them as + training and validation JSONL files. + 3. Polls the job to completion and prints every generated file output. + 4. Cleans up the generated fine-tuning files, the Azure OpenAI input file, and the data generation job. + + `simple_qna` REQUIRES `model_options` — the service uses the configured LLM + to synthesize the QnA pairs. Setting `train_split` triggers a split of + the generated samples into two Azure OpenAI output files. + +USAGE: + python sample_dataset_generation_job_simpleqna_for_finetuning.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity openai 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) FOUNDRY_MODEL_NAME - Required. The name of an Azure OpenAI model + deployment used to synthesize the QnA samples. For `simple_qna` fine-tuning, + the deployment must support the chat completions API (e.g. `gpt-4o`, `gpt-4.1`). + 3) DATASET_NAME - Optional. Name to assign to the generated output files + (used as the file name prefix). Defaults to `simpleqna-finetuning-sample`. + The service caps the rendered output name at 50 characters, so keep + custom values short — the sample appends a unique run id suffix. + 4) POLL_INTERVAL_SECONDS - Optional. Number of seconds to sleep between status + polls for the data generation job. Defaults to 10. +""" + +import io +import os +import time +import uuid +from datetime import datetime, timezone + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOutputOptions, + DataGenerationJobScenario, + DataGenerationModelOptions, + FileDataGenerationJobOutput, + FileDataGenerationJobSource, + JobStatus, + SimpleQnADataGenerationJobOptions, + SimpleQnAFineTuningQuestionType, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +dataset_name = os.environ.get("DATASET_NAME", "simpleqna-finetuning-sample") +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run output name so repeated runs do not collide. +# Output names are capped at 50 characters by the service. +run_id = f"{datetime.now(tz=timezone.utc).strftime('%y%m%d%H%M%S')}-{uuid.uuid4().hex[:4]}" +output_name = f"{dataset_name}-{run_id}" +if len(output_name) > 50: + raise ValueError( + f"Output name `{output_name}` exceeds the 50-character service limit. " + f"Lower DATASET_NAME (currently `{dataset_name}`) so that `-` fits within 50 characters." + ) + +# Reference document the sample uploads as an Azure OpenAI file. The service +# requires the file to contain at least 1 KB of content to generate QnA from. +SEED_REFERENCE_DOCUMENT = """# Widgets and Gizmos Reference + +## Products +- Widget: blue, manufactured at Factory 7 in Acme, carbon-fiber, rated to 80 C, sold in packs of 4, 250 g each. +- Gizmo: red, manufactured at Factory 12 in Bedrock, carbon-fiber, rated to 80 C, sold individually, 1.2 kg each. +- Sprocket: green, manufactured at Factory 3 in Acme, stainless steel, rated to 200 C, sold individually, 500 g each. + +## Operations +- Factory operates weekdays 0700-1900 local time. +- Closed on public holidays, except for the annual maintenance run on December 27. +- ISO 9001 certified; audited annually by an independent third party. +- Quality control samples every 100th unit and runs full destructive testing on every 5000th unit. + +## Customer support +- Warranty claims: email support@example.com with the serial number printed on the underside of the product. +- Returns: accepted within 30 days if unopened; opened items are eligible for repair only. +- Bulk orders (50+ units): contact sales@example.com for volume pricing and an extended 90-day return window. +- Replacement parts: orderable directly from the support portal using the original order number. + +## Pricing and SLAs +- Widget pack: USD 24.99 per 4-pack; free shipping on orders over USD 75. +- Gizmo unit: USD 49.99; free shipping on orders over USD 75. +- Sprocket unit: USD 14.99; ships from regional warehouses in 1-2 business days. +- Standard support response: within one business day. Priority support response: within four hours. +""" + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + + # ------------------------------------------------------------------ + # 1. Upload the seed reference document as an Azure OpenAI file. + # ------------------------------------------------------------------ + seed_filename = f"widgets-gizmos-seed-{run_id}.md" + print(f"Upload the seed reference document as Azure OpenAI file `{seed_filename}`.") + seed_file = openai_client.files.create( + file=(seed_filename, io.BytesIO(SEED_REFERENCE_DOCUMENT.encode("utf-8"))), + purpose="user_data", + ) + print(f"Uploaded Azure OpenAI file (id: {seed_file.id}).") + + # Wait for the file to finish processing — the data generation service + # rejects references to files that are not yet in the `processed` state. + print("Wait for the Azure OpenAI file to be processed.", end="", flush=True) + while seed_file.status not in ("processed", "error"): + time.sleep(2) + seed_file = openai_client.files.retrieve(file_id=seed_file.id) + print(".", end="", flush=True) + print() + if seed_file.status != "processed": + raise RuntimeError(f"Azure OpenAI file `{seed_file.id}` failed to process: status=`{seed_file.status}`.") + + # ------------------------------------------------------------------ + # 2. Submit a fine-tuning data generation job that consumes the file. + # ------------------------------------------------------------------ + print("Create a fine-tuning data generation job from the Azure OpenAI file.") + job = DataGenerationJob( + inputs=DataGenerationJobInputs( + name=f"simpleqna-finetuning-{run_id}", + scenario=DataGenerationJobScenario.SUPERVISED_FINETUNING, + sources=[ + FileDataGenerationJobSource( + description="Widgets & Gizmos product / operations reference (Azure OpenAI file).", + id=seed_file.id, + ), + ], + options=SimpleQnADataGenerationJobOptions( + # Service requires max_samples to be between 15 and 1000. + max_samples=15, + # `simple_qna` REQUIRES model_options. + model_options=DataGenerationModelOptions(model=model_name), + # Split generated samples 80% training / 20% validation. + train_split=0.8, + # Ask for both short-answer and long-answer questions. + question_types=[ + SimpleQnAFineTuningQuestionType.SHORT_ANSWER, + SimpleQnAFineTuningQuestionType.LONG_ANSWER, + ], + ), + output_options=DataGenerationJobOutputOptions(name=output_name), + ), + ) + job = project_client.beta.datasets.create_generation_job(job=job) + print(f"Created data generation job `{job.id}` (status: `{job.status}`).") + + print(f"Poll job `{job.id}` until it reaches a terminal state.", end="", flush=True) + while True: + job = project_client.beta.datasets.get_generation_job(job_id=job.id) + if job.status in TERMINAL_STATUSES: + break + time.sleep(poll_interval_seconds) + print(".", end="", flush=True) + print() + print(f"Final job status: `{job.status}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Job `{job.id}` ended with status `{job.status}`: {message}") + + # ------------------------------------------------------------------ + # 3. Inspect the generated fine-tuning file outputs. + # ------------------------------------------------------------------ + # `train_split=0.8` produces two Azure OpenAI files: a training partition + # and a validation partition. Both are emitted as FileDataGenerationJobOutput + # entries in `job.result.outputs`. + file_outputs = [ + output + for output in ((job.result.outputs if job.result is not None else None) or []) + if isinstance(output, FileDataGenerationJobOutput) + ] + if not file_outputs: + raise RuntimeError(f"Job `{job.id}` did not produce any file outputs.") + + print(f"Generated {len(file_outputs)} fine-tuning file(s):") + for output in file_outputs: + if not output.id: + raise RuntimeError(f"Job `{job.id}` returned a file output without an id.") + # Resolve the Azure OpenAI file to surface its real filename and size. + file_info = openai_client.files.retrieve(file_id=output.id) + print(f" - filename=`{file_info.filename}` id=`{output.id}` bytes={file_info.bytes}") + if job.result is not None and job.result.generated_samples is not None: + print(f"Generated samples: {job.result.generated_samples}") + + # ------------------------------------------------------------------ + # 4. Clean up. + # ------------------------------------------------------------------ + for output in file_outputs: + print(f"Delete the generated Azure OpenAI file `{output.id}`.") + openai_client.files.delete(file_id=output.id) + + print(f"Delete the Azure OpenAI input file `{seed_file.id}`.") + openai_client.files.delete(file_id=seed_file.id) + + print(f"Delete the data generation job `{job.id}`.") + project_client.beta.datasets.delete_generation_job(job_id=job.id) diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_agent_source.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_agent_source.py new file mode 100644 index 000000000000..70063d32da26 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_agent_source.py @@ -0,0 +1,209 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Generates an evaluation dataset from a prompt agent's definition using the + `simple_qna` recipe. The sample is fully self-contained — it creates a + short-lived `PromptAgentDefinition` whose `instructions` give the service + enough material to synthesize QnA pairs, then uses that agent as the + source for the data generation job. The sample: + + 1. Creates a `PromptAgentDefinition` agent with domain-specific + instructions (a small Widgets & Gizmos customer-support persona). + 2. Creates a `DataGenerationJob` (scenario=EVALUATION, type=simple_qna) + whose source is an `Agent` reference pointing at the new agent. The + service fetches the agent's instructions / prompt and uses the + configured LLM to synthesize question / answer pairs from them. + 3. Polls the job to completion and resolves the resulting `DatasetVersion`. + 4. Cleans up the data generation job, the generated dataset, and the agent version. + + `simple_qna` REQUIRES `model_options`. For `simple_qna` evaluation jobs the + deployed model must support the Azure OpenAI Responses API. See the + supported-model list: + https://learn.microsoft.com/azure/foundry/openai/how-to/responses?tabs=python-key#model-support + + If you want to synthesize QnA from an agent's recorded conversation traces + instead of its definition, see + `sample_dataset_generation_job_traces_for_evaluation.py` (traces recipe). + +USAGE: + python sample_dataset_generation_job_simpleqna_with_agent_source.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of an Azure OpenAI model + deployment used both as the prompt agent's backing model and to synthesize + the QnA samples. For `simple_qna` evaluation, choose a Responses-API + capable model (see the link in the description). + 3) DATASET_NAME - Optional. Name to assign to the generated output dataset. + Defaults to `simpleqna-agent-source-sample`. The service caps the + rendered output name at 50 characters, so keep custom values short — + the sample appends a unique run id suffix. + 4) POLL_INTERVAL_SECONDS - Optional. Number of seconds to sleep between status + polls for the data generation job. Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timezone + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + AgentDataGenerationJobSource, + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOutputOptions, + DataGenerationJobScenario, + DataGenerationModelOptions, + DatasetDataGenerationJobOutput, + DatasetVersion, + JobStatus, + PromptAgentDefinition, + SimpleQnADataGenerationJobOptions, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +dataset_name = os.environ.get("DATASET_NAME", "simpleqna-agent-source-sample") +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run names so repeated runs do not collide. +# Output names are capped at 50 characters by the service. +run_id = f"{datetime.now(tz=timezone.utc).strftime('%y%m%d%H%M%S')}-{uuid.uuid4().hex[:4]}" +output_dataset_name = f"{dataset_name}-{run_id}" +if len(output_dataset_name) > 50: + raise ValueError( + f"Output dataset name `{output_dataset_name}` exceeds the 50-character service limit. " + f"Lower DATASET_NAME (currently `{dataset_name}`) so that `-` fits within 50 characters." + ) + +# The prompt agent's instructions seed the QnA generation. Make them concrete +# and domain-specific so the service has enough material to synthesize from. +AGENT_INSTRUCTIONS = """You are a customer support assistant for Acme's "Widgets & Gizmos" product line. + +Product catalog you can answer about: +- Widget: blue, manufactured at Factory 7 in Acme, carbon-fiber, rated to 80 C, sold in packs of 4, 250 g each, USD 24.99 per pack. +- Gizmo: red, manufactured at Factory 12 in Bedrock, carbon-fiber, rated to 80 C, sold individually, 1.2 kg each, USD 49.99. +- Sprocket: green, manufactured at Factory 3 in Acme, stainless steel, rated to 200 C, sold individually, 500 g each, USD 14.99. + +Operational policy: +- Factory operates weekdays 0700-1900 local time and is closed on public holidays except the annual maintenance run on December 27. +- Warranty claims must include the serial number printed on the underside of the product, emailed to support@example.com. +- Returns are accepted within 30 days if unopened; opened items are eligible for repair only. +- Bulk orders of 50 or more units use the sales@example.com channel and get an extended 90-day return window. +- Standard support responds within one business day; priority support responds within four hours. +- Free shipping on orders over USD 75. + +When asked about anything outside this catalog and policy, politely say you do not have that information. +""" + +agent_name = f"widgets-gizmos-support-{run_id}" + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, +): + + # ------------------------------------------------------------------ + # 1. Create a short-lived prompt agent to act as the source. + # ------------------------------------------------------------------ + print(f"Create prompt agent `{agent_name}`.") + agent = project_client.agents.create_version( + agent_name=agent_name, + definition=PromptAgentDefinition( + model=model_name, + instructions=AGENT_INSTRUCTIONS, + ), + ) + print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version}).") + + try: + # ------------------------------------------------------------------ + # 2. Submit a SimpleQnA data generation job sourced from the agent. + # ------------------------------------------------------------------ + # The service fetches the agent's instructions / prompt and uses + # `model_options.model` to synthesize QnA pairs from them. + print(f"Create a SimpleQnA evaluation job sourced from agent `{agent.name}` (version {agent.version}).") + job = DataGenerationJob( + inputs=DataGenerationJobInputs( + name=f"simpleqna-agent-{run_id}", + scenario=DataGenerationJobScenario.EVALUATION, + sources=[ + AgentDataGenerationJobSource( + description="Agent definition (instructions / prompt) used to seed QnA generation.", + agent_name=agent.name, + agent_version=agent.version, + ), + ], + options=SimpleQnADataGenerationJobOptions( + # Service requires max_samples to be between 15 and 1000. + max_samples=15, + # `simple_qna` REQUIRES model_options. + model_options=DataGenerationModelOptions(model=model_name), + ), + output_options=DataGenerationJobOutputOptions(name=output_dataset_name), + ), + ) + job = project_client.beta.datasets.create_generation_job(job=job) + print(f"Created data generation job `{job.id}` (status: `{job.status}`).") + + print(f"Poll job `{job.id}` until it reaches a terminal state.", end="", flush=True) + while True: + job = project_client.beta.datasets.get_generation_job(job_id=job.id) + if job.status in TERMINAL_STATUSES: + break + time.sleep(poll_interval_seconds) + print(".", end="", flush=True) + print() + print(f"Final job status: `{job.status}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Job `{job.id}` ended with status `{job.status}`: {message}") + + # Locate the Dataset output produced by the job. + output_name: str = "" + output_version: str = "" + for output in (job.result.outputs if job.result is not None else None) or []: + if isinstance(output, DatasetDataGenerationJobOutput): + output_name = output.name or "" + output_version = output.version or "" + break + if not output_name or not output_version: + raise RuntimeError(f"Job `{job.id}` did not produce a dataset output.") + + dataset: DatasetVersion = project_client.datasets.get(name=output_name, version=output_version) + print(f"Generated dataset: name=`{dataset.name}` version=`{dataset.version}` id=`{dataset.id}`") + if job.result is not None and job.result.generated_samples is not None: + print(f"Generated samples: {job.result.generated_samples}") + + # ------------------------------------------------------------------ + # 3. Clean up the generated dataset and the data generation job + # (the agent is deleted in the `finally` block below). + # ------------------------------------------------------------------ + print(f"Delete the generated dataset `{dataset.name}` v{dataset.version}.") + project_client.datasets.delete(name=dataset.name or "", version=dataset.version or "") + + print(f"Delete the data generation job `{job.id}`.") + project_client.beta.datasets.delete_generation_job(job_id=job.id) + finally: + # The agent is short-lived — always delete it, even if the job failed. + print(f"Delete the prompt agent `{agent.name}` (version {agent.version}).") + project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version) diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_file_source.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_file_source.py new file mode 100644 index 000000000000..f52d331e2603 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_file_source.py @@ -0,0 +1,238 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Generates an evaluation dataset from a multi-source `simple_qna` job that + combines an Azure OpenAI File with an inline Prompt. The sample: + + 1. Uploads a short Markdown reference document via the Azure OpenAI Files + API (`purpose=user_data`) so it can be referenced by file id. + 2. Creates a `DataGenerationJob` (scenario=EVALUATION, type=simple_qna) + with two sources: the uploaded `File` and a `Prompt` that adds an + instruction to generate expert-level, high-difficulty questions. + 3. Polls the job to completion, resolves the generated `DatasetVersion`, + and shows that the caller-supplied output `description` and `tags` are + propagated onto the new dataset. + 4. Cleans up the generated dataset, the Azure OpenAI input file, and the data generation job. + + `simple_qna` REQUIRES `model_options` — the service uses the configured LLM + to synthesize question / answer pairs from the combined sources. + + For `simple_qna` evaluation jobs the deployed model must support the + Azure OpenAI Responses API. See the supported-model list: + https://learn.microsoft.com/azure/foundry/openai/how-to/responses?tabs=python-key#model-support + +USAGE: + python sample_dataset_generation_job_simpleqna_with_file_source.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity openai 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) FOUNDRY_MODEL_NAME - Required. The name of an Azure OpenAI model + deployment used to synthesize the QnA samples. For `simple_qna` evaluation, + choose a Responses-API capable model (see the link in the description). + 3) DATASET_NAME - Optional. Name to assign to the generated output dataset. + Defaults to `simpleqna-file-source-sample`. The service caps the rendered + output name at 50 characters, so keep custom values short — the sample + appends a unique run id suffix. + 4) POLL_INTERVAL_SECONDS - Optional. Number of seconds to sleep between status + polls for the data generation job. Defaults to 10. +""" + +import io +import os +import time +import uuid +from datetime import datetime, timezone + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOutputOptions, + DataGenerationJobScenario, + DataGenerationModelOptions, + DatasetDataGenerationJobOutput, + DatasetVersion, + FileDataGenerationJobSource, + JobStatus, + PromptDataGenerationJobSource, + SimpleQnADataGenerationJobOptions, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +dataset_name = os.environ.get("DATASET_NAME", "simpleqna-file-source-sample") +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run resource names so repeated runs do not collide. +# Output names are capped at 50 characters by the service. +run_id = f"{datetime.now(tz=timezone.utc).strftime('%y%m%d%H%M%S')}-{uuid.uuid4().hex[:4]}" +output_dataset_name = f"{dataset_name}-{run_id}" +if len(output_dataset_name) > 50: + raise ValueError( + f"Output dataset name `{output_dataset_name}` exceeds the 50-character service limit. " + f"Lower DATASET_NAME (currently `{dataset_name}`) so that `-` fits within 50 characters." + ) + +# Reference document the sample uploads as an Azure OpenAI file. The service +# requires the file to contain at least 1 KB of content to generate QnA from. +SEED_REFERENCE_DOCUMENT = """# Widgets and Gizmos Reference + +## Products +- Widget: blue, manufactured at Factory 7 in Acme, carbon-fiber, rated to 80 C, sold in packs of 4, 250 g each. +- Gizmo: red, manufactured at Factory 12 in Bedrock, carbon-fiber, rated to 80 C, sold individually, 1.2 kg each. +- Sprocket: green, manufactured at Factory 3 in Acme, stainless steel, rated to 200 C, sold individually, 500 g each. + +## Operations +- Factory operates weekdays 0700-1900 local time. +- Closed on public holidays, except for the annual maintenance run on December 27. +- ISO 9001 certified; audited annually by an independent third party. +- Quality control samples every 100th unit and runs full destructive testing on every 5000th unit. + +## Customer support +- Warranty claims: email support@example.com with the serial number printed on the underside of the product. +- Returns: accepted within 30 days if unopened; opened items are eligible for repair only. +- Bulk orders (50+ units): contact sales@example.com for volume pricing and an extended 90-day return window. +- Replacement parts: orderable directly from the support portal using the original order number. + +## Pricing and SLAs +- Widget pack: USD 24.99 per 4-pack; free shipping on orders over USD 75. +- Gizmo unit: USD 49.99; free shipping on orders over USD 75. +- Sprocket unit: USD 14.99; ships from regional warehouses in 1-2 business days. +- Standard support response: within one business day. Priority support response: within four hours. +""" + +EXPECTED_OUTPUT_DESCRIPTION = "Expert-level QnA pairs generated from the Widgets & Gizmos reference." +EXPECTED_OUTPUT_TAGS = {"sample": "dataset-generation-simpleqna-with-file-source", "difficulty": "expert"} + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + + # ------------------------------------------------------------------ + # 1. Upload the seed reference document as an Azure OpenAI file. + # ------------------------------------------------------------------ + seed_filename = f"widgets-gizmos-seed-{run_id}.md" + print(f"Upload the seed reference document as Azure OpenAI file `{seed_filename}`.") + seed_file = openai_client.files.create( + file=(seed_filename, io.BytesIO(SEED_REFERENCE_DOCUMENT.encode("utf-8"))), + purpose="user_data", + ) + print(f"Uploaded Azure OpenAI file (id: {seed_file.id}).") + + # Wait for the file to finish processing — the data generation service + # rejects references to files that are not yet in the `processed` state. + print("Wait for the Azure OpenAI file to be processed.", end="", flush=True) + while seed_file.status not in ("processed", "error"): + time.sleep(2) + seed_file = openai_client.files.retrieve(file_id=seed_file.id) + print(".", end="", flush=True) + print() + if seed_file.status != "processed": + raise RuntimeError(f"Azure OpenAI file `{seed_file.id}` failed to process: status=`{seed_file.status}`.") + + # ------------------------------------------------------------------ + # 2. Submit a multi-source SimpleQnA data generation job. + # ------------------------------------------------------------------ + # Two sources are combined for a single job: + # - The File source contributes the source material (the reference + # document uploaded above). + # - The Prompt source contributes a steering instruction (difficulty). + print("Create a multi-source data generation job (File + Prompt).") + job = DataGenerationJob( + inputs=DataGenerationJobInputs( + name=f"simpleqna-multisource-{run_id}", + scenario=DataGenerationJobScenario.EVALUATION, + sources=[ + FileDataGenerationJobSource( + description="Widgets & Gizmos product / operations reference (Azure OpenAI file).", + id=seed_file.id, + ), + PromptDataGenerationJobSource( + description="Specifies the question difficulty for SimpleQnA generation.", + prompt="Generate expert-level questions of high difficulty.", + ), + ], + options=SimpleQnADataGenerationJobOptions( + # Service requires max_samples to be between 15 and 1000. + max_samples=15, + # `simple_qna` REQUIRES model_options. + model_options=DataGenerationModelOptions(model=model_name), + ), + output_options=DataGenerationJobOutputOptions( + name=output_dataset_name, + description=EXPECTED_OUTPUT_DESCRIPTION, + tags=EXPECTED_OUTPUT_TAGS, + ), + ), + ) + job = project_client.beta.datasets.create_generation_job(job=job) + print(f"Created data generation job `{job.id}` (status: `{job.status}`).") + + print(f"Poll job `{job.id}` until it reaches a terminal state.", end="", flush=True) + while True: + job = project_client.beta.datasets.get_generation_job(job_id=job.id) + if job.status in TERMINAL_STATUSES: + break + time.sleep(poll_interval_seconds) + print(".", end="", flush=True) + print() + print(f"Final job status: `{job.status}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Job `{job.id}` ended with status `{job.status}`: {message}") + + # Locate the Dataset output produced by the job. + output_name: str = "" + output_version: str = "" + for output in (job.result.outputs if job.result is not None else None) or []: + if isinstance(output, DatasetDataGenerationJobOutput): + output_name = output.name or "" + output_version = output.version or "" + break + if not output_name or not output_version: + raise RuntimeError(f"Job `{job.id}` did not produce a dataset output.") + + # ------------------------------------------------------------------ + # 3. Inspect the generated dataset and show metadata propagation. + # ------------------------------------------------------------------ + # The caller-supplied output `description` and `tags` are persisted onto + # the generated dataset. The service also automatically adds a + # `data_generation_job_id` tag pointing back at this job. + dataset: DatasetVersion = project_client.datasets.get(name=output_name, version=output_version) + print(f"Generated dataset: name=`{dataset.name}` version=`{dataset.version}` id=`{dataset.id}`") + print(f" description: {dataset.description}") + print(f" tags: {dataset.tags}") + if job.result is not None and job.result.generated_samples is not None: + print(f"Generated samples: {job.result.generated_samples}") + + # ------------------------------------------------------------------ + # 4. Clean up. + # ------------------------------------------------------------------ + print(f"Delete the generated dataset `{dataset.name}` v{dataset.version}.") + project_client.datasets.delete(name=dataset.name or "", version=dataset.version or "") + + print(f"Delete the Azure OpenAI input file `{seed_file.id}`.") + openai_client.files.delete(file_id=seed_file.id) + + print(f"Delete the data generation job `{job.id}`.") + project_client.beta.datasets.delete_generation_job(job_id=job.id) diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_prompt_source.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_prompt_source.py new file mode 100644 index 000000000000..a4cb9bb00b68 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_simpleqna_with_prompt_source.py @@ -0,0 +1,272 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + End-to-end scenario combining `.beta.datasets` data generation with an + evaluation run. The sample: + + 1. Creates a `DataGenerationJob` (scenario=EVALUATION, type=simple_qna) that + synthesizes question/answer pairs from an inline prompt and writes them + to a new versioned Dataset. + 2. Polls the job to completion and resolves the resulting `DatasetVersion`. + 3. Creates an OpenAI evaluation (`client.evals.create`) with builtin + Azure AI evaluators. + 4. Runs the evaluation against the generated dataset by passing the + dataset's id as the run's `file_id`. + 5. Cleans up the evaluation, the generated dataset, and the data generation job. + +USAGE: + python sample_dataset_generation_job_simpleqna_with_prompt_source.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of an Azure OpenAI model + deployment used both to generate the QnA samples and as the judge model + for builtin evaluators. For `simple_qna` evaluation jobs the deployed + model must support the Azure OpenAI Responses API. See the supported-model + list: https://learn.microsoft.com/azure/foundry/openai/how-to/responses?tabs=python-key#model-support + 3) DATASET_NAME - Optional. Name to assign to the generated output dataset. + Defaults to `dataset-generation-eval-sample`. + 4) POLL_INTERVAL_SECONDS - Optional. Number of seconds to sleep between status + polls for both the data generation job and the evaluation run. Defaults to 10. +""" + +import os +import time + +from dotenv import load_dotenv +from openai.types.eval_create_params import DataSourceConfigCustom +from openai.types.evals.create_eval_completions_run_data_source_param import ( + CreateEvalCompletionsRunDataSourceParam, + InputMessagesTemplate, + InputMessagesTemplateTemplateEvalItem, + SourceFileID, +) +from openai.types.responses.response_input_text_param import ResponseInputTextParam + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOutputOptions, + DataGenerationJobScenario, + DataGenerationModelOptions, + DatasetDataGenerationJobOutput, + DatasetVersion, + JobStatus, + PromptDataGenerationJobSource, + SimpleQnADataGenerationJobOptions, + TestingCriterionAzureAIEvaluator, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +dataset_name = os.environ.get("DATASET_NAME", "dataset-generation-eval-sample") +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + + # ------------------------------------------------------------------ + # 1. Generate a QnA evaluation dataset from an inline prompt. + # ------------------------------------------------------------------ + print("Create a data generation job.") + job = DataGenerationJob( + inputs=DataGenerationJobInputs( + name="qna-from-policy-prompt", + scenario=DataGenerationJobScenario.EVALUATION, + sources=[ + PromptDataGenerationJobSource( + description="Contoso refund policy", + prompt=( + "Contoso offers a full refund within 30 days of purchase for any product " + "returned in its original condition. After 30 days, store credit may be " + "issued at the discretion of customer support. Digital goods are " + "non-refundable once downloaded." + ), + ), + ], + options=SimpleQnADataGenerationJobOptions( + # Service requires max_samples to be between 15 and 1000. + max_samples=15, + model_options=DataGenerationModelOptions(model=model_name), + ), + output_options=DataGenerationJobOutputOptions( + name=dataset_name, + description="QnA pairs generated from the Contoso refund policy prompt.", + tags={"sample": "dataset-generation-with-evaluation"}, + ), + ), + ) + job = project_client.beta.datasets.create_generation_job(job=job) + print(f"Created data generation job `{job.id}` (status: `{job.status}`).") + + print(f"Poll job `{job.id}` until it reaches a terminal state.", end="", flush=True) + while True: + job = project_client.beta.datasets.get_generation_job(job_id=job.id) + if job.status in TERMINAL_STATUSES: + break + time.sleep(poll_interval_seconds) + print(".", end="", flush=True) + print() + print(f"Final job status: `{job.status}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Job `{job.id}` ended with status `{job.status}`: {message}") + + # Locate the Dataset output produced by the job. + output_name: str = "" + output_version: str = "" + for output in (job.result.outputs if job.result is not None else None) or []: + if isinstance(output, DatasetDataGenerationJobOutput): + output_name = output.name or "" + output_version = output.version or "" + break + if not output_name or not output_version: + raise RuntimeError(f"Job `{job.id}` did not produce a dataset output.") + + # Resolve the DatasetVersion so we can use its id as the eval run's file_id. + dataset: DatasetVersion = project_client.datasets.get(name=output_name, version=output_version) + print(f"Generated dataset: name=`{dataset.name}` version=`{dataset.version}` id=`{dataset.id}`") + + # ------------------------------------------------------------------ + # 2. Create an evaluation that scores the model's answers to the + # generated questions. + # ------------------------------------------------------------------ + # The `simple_qna` generator produces records with `query` and `ground_truth` + # fields. The evaluation run below sends each `query` through a model target + # to produce a response, and the evaluators score that response. + data_source_config = DataSourceConfigCustom( + type="custom", + item_schema={ + "type": "object", + "properties": { + "query": {"type": "string"}, + "ground_truth": {"type": "string"}, + }, + "required": ["query"], + }, + include_sample_schema=True, + ) + + testing_criteria = [ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="coherence", + evaluator_name="builtin.coherence", + initialization_parameters={"deployment_name": model_name}, + data_mapping={"query": "{{item.query}}", "response": "{{sample.output_text}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="fluency", + evaluator_name="builtin.fluency", + initialization_parameters={"deployment_name": model_name}, + data_mapping={"response": "{{sample.output_text}}"}, + ), + ] + + print("Create the evaluation.") + eval_object = openai_client.evals.create( + name="generated-qna-evaluation", + data_source_config=data_source_config, + testing_criteria=testing_criteria, + ) + print(f"Evaluation created (id: {eval_object.id}).") + + # ------------------------------------------------------------------ + # 3. Run the evaluation against the generated dataset. + # ------------------------------------------------------------------ + # `completions` data source: for each item in the dataset, render the + # input_messages template, send to `model`, and feed the response into + # the testing criteria as `sample.output_text`. + print(f"Create an evaluation run that consumes dataset `{dataset.id}`.") + input_message = InputMessagesTemplate( + type="template", + template=[ + InputMessagesTemplateTemplateEvalItem( + type="message", + role="developer", + content=ResponseInputTextParam( + type="input_text", + text=( + "You are a Contoso customer-support assistant. Answer the user's " + "question about the Contoso refund policy clearly and concisely." + ), + ), + ), + InputMessagesTemplateTemplateEvalItem( + type="message", + role="user", + content=ResponseInputTextParam( + type="input_text", + text="{{item.query}}", + ), + ), + ], + ) + data_source = CreateEvalCompletionsRunDataSourceParam( + type="completions", + source=SourceFileID(type="file_id", id=dataset.id or ""), + input_messages=input_message, + model=model_name, + ) + eval_run = openai_client.evals.runs.create( + eval_id=eval_object.id, + name="generated-qna-evaluation-run", + data_source=data_source, + ) + print(f"Evaluation run created (id: {eval_run.id}).") + + while eval_run.status not in ("completed", "failed"): + time.sleep(poll_interval_seconds) + eval_run = openai_client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + print(f"Final eval run status: `{eval_run.status}`.") + + if eval_run.status == "completed": + print(f"Result counts: {eval_run.result_counts}") + print(f"Eval run report URL: {eval_run.report_url}") + output_items = list(openai_client.evals.runs.output_items.list(run_id=eval_run.id, eval_id=eval_object.id)) + print(f"Output items (total: {len(output_items)}):") + # Print a per-item summary (avoid pprint on the full payload to keep the + # output ASCII-safe on Windows consoles and easy to scan). + for idx, item in enumerate(output_items, start=1): + results = getattr(item, "results", None) or [] + scores = ", ".join( + f"{r.get('name', '?')}={r.get('score', 'n/a')} ({r.get('passed', 'n/a')})" + for r in results + if isinstance(r, dict) + ) + print(f" item {idx}: status={item.status} | {scores}") + else: + print("Evaluation run did not complete successfully.") + + # ------------------------------------------------------------------ + # 4. Clean up. + # ------------------------------------------------------------------ + print(f"Delete evaluation `{eval_object.id}`.") + openai_client.evals.delete(eval_id=eval_object.id) + + print(f"Delete the generated dataset `{dataset.name}` v{dataset.version}.") + project_client.datasets.delete(name=dataset.name or "", version=dataset.version or "") + + print(f"Delete the data generation job `{job.id}`.") + project_client.beta.datasets.delete_generation_job(job_id=job.id) diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_evaluation.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_evaluation.py new file mode 100644 index 000000000000..9b2ca86a89bf --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_evaluation.py @@ -0,0 +1,160 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Generates an evaluation dataset from an agent's recent conversation + traces. The sample: + + 1. Creates a `DataGenerationJob` (scenario=EVALUATION, type=traces) that + reads spans from Application Insights for an existing agent within a + time window and synthesizes question / answer pairs into a new + versioned Dataset. + 2. Polls the job to completion and resolves the resulting `DatasetVersion`. + 3. Cleans up the generated dataset and the data generation job. + + The Traces source consumes existing telemetry, so no `model_options` are + required — the service derives samples directly from the agent's traces. + The agent must have at least one trace recorded within the configured + look-back window or the job will succeed with zero generated samples. + +USAGE: + python sample_dataset_generation_job_traces_for_evaluation.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_AGENT_NAME - Required. The name of an agent (Foundry Agent or + OpenTelemetry-instrumented third-party agent) that has recent + conversation traces in Application Insights. + 3) DATASET_NAME - Optional. Name to assign to the generated output dataset. + Defaults to `traces-eval-sample`. The service caps the rendered output + name at 50 characters, so keep custom values short — the sample appends + a unique run id suffix. + 4) FOUNDRY_TRACES_WINDOW_DAYS - Optional. How far back, in days, to look for + agent traces. Defaults to 7. + 5) POLL_INTERVAL_SECONDS - Optional. Number of seconds to sleep between status + polls for the data generation job. Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timedelta, timezone + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOutputOptions, + DataGenerationJobScenario, + DatasetDataGenerationJobOutput, + DatasetVersion, + JobStatus, + TracesDataGenerationJobOptions, + TracesDataGenerationJobSource, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +agent_name = os.environ["FOUNDRY_AGENT_NAME"] +dataset_name = os.environ.get("DATASET_NAME", "traces-eval-sample") +traces_window_days = int(os.environ.get("FOUNDRY_TRACES_WINDOW_DAYS", "7")) +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run output dataset name so repeated runs do not collide. +# Output names are capped at 50 characters by the service. +run_id = f"{datetime.now(tz=timezone.utc).strftime('%y%m%d%H%M%S')}-{uuid.uuid4().hex[:4]}" +output_dataset_name = f"{dataset_name}-{run_id}" +if len(output_dataset_name) > 50: + raise ValueError( + f"Output dataset name `{output_dataset_name}` exceeds the 50-character service limit. " + f"Lower DATASET_NAME (currently `{dataset_name}`) so that `-` fits within 50 characters." + ) + +# Trace look-back window: now - `traces_window_days` ... now. +end_time = datetime.now(tz=timezone.utc) +start_time = end_time - timedelta(days=traces_window_days) + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, +): + + # ------------------------------------------------------------------ + # 1. Submit a data generation job that reads agent traces. + # ------------------------------------------------------------------ + print(f"Create a data generation job from traces for agent `{agent_name}` (window: {traces_window_days} day(s)).") + job = DataGenerationJob( + inputs=DataGenerationJobInputs( + name=f"traces-eval-{run_id}", + scenario=DataGenerationJobScenario.EVALUATION, + sources=[ + TracesDataGenerationJobSource( + description="Application Insights conversation traces for the Foundry agent.", + agent_name=agent_name, + start_time=start_time, + end_time=end_time, + ), + ], + options=TracesDataGenerationJobOptions( + # Service requires max_samples to be between 15 and 1000. + max_samples=15, + ), + output_options=DataGenerationJobOutputOptions(name=output_dataset_name), + ), + ) + job = project_client.beta.datasets.create_generation_job(job=job) + print(f"Created data generation job `{job.id}` (status: `{job.status}`).") + + print(f"Poll job `{job.id}` until it reaches a terminal state.", end="", flush=True) + while True: + job = project_client.beta.datasets.get_generation_job(job_id=job.id) + if job.status in TERMINAL_STATUSES: + break + time.sleep(poll_interval_seconds) + print(".", end="", flush=True) + print() + print(f"Final job status: `{job.status}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Job `{job.id}` ended with status `{job.status}`: {message}") + + # Locate the Dataset output produced by the job. + output_name: str = "" + output_version: str = "" + for output in (job.result.outputs if job.result is not None else None) or []: + if isinstance(output, DatasetDataGenerationJobOutput): + output_name = output.name or "" + output_version = output.version or "" + break + if not output_name or not output_version: + raise RuntimeError(f"Job `{job.id}` did not produce a dataset output.") + + dataset: DatasetVersion = project_client.datasets.get(name=output_name, version=output_version) + print(f"Generated dataset: name=`{dataset.name}` version=`{dataset.version}` id=`{dataset.id}`") + if job.result is not None and job.result.generated_samples is not None: + print(f"Generated samples: {job.result.generated_samples}") + + # ------------------------------------------------------------------ + # 2. Clean up. + # ------------------------------------------------------------------ + print(f"Delete the generated dataset `{dataset.name}` v{dataset.version}.") + project_client.datasets.delete(name=dataset.name or "", version=dataset.version or "") + + print(f"Delete the data generation job `{job.id}`.") + project_client.beta.datasets.delete_generation_job(job_id=job.id) diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_finetuning.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_finetuning.py new file mode 100644 index 000000000000..d4f7cf4c1a73 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_dataset_generation_job_traces_for_finetuning.py @@ -0,0 +1,173 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Generates supervised fine-tuning data from an agent's recent + conversation traces. The sample: + + 1. Creates a `DataGenerationJob` (scenario=SUPERVISED_FINETUNING, + type=traces) that reads spans from Application Insights for an + existing agent within a time window and emits ready-to-use fine-tuning + JSONL files split into training and validation partitions. + 2. Polls the job to completion and prints every generated file output. + 3. Cleans up the generated fine-tuning files and the data generation job. + + Setting `train_split` triggers a split of the generated samples into two + Azure OpenAI files — a training partition and a validation partition. + The Traces source consumes existing telemetry, so no `model_options` are + required. + +USAGE: + python sample_dataset_generation_job_traces_for_finetuning.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_AGENT_NAME - Required. The name of an agent (Foundry Agent or + OpenTelemetry-instrumented third-party agent) that has recent + conversation traces in Application Insights. + 3) DATASET_NAME - Optional. Name to assign to the generated output files + (used as the file name prefix). Defaults to `traces-finetuning-sample`. + The service caps the rendered output name at 50 characters, so keep + custom values short — the sample appends a unique run id suffix. + 4) FOUNDRY_TRACES_WINDOW_DAYS - Optional. How far back, in days, to look for + agent traces. Defaults to 7. + 5) POLL_INTERVAL_SECONDS - Optional. Number of seconds to sleep between status + polls for the data generation job. Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timedelta, timezone + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + DataGenerationJob, + DataGenerationJobInputs, + DataGenerationJobOutputOptions, + DataGenerationJobScenario, + FileDataGenerationJobOutput, + JobStatus, + TracesDataGenerationJobOptions, + TracesDataGenerationJobSource, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +agent_name = os.environ["FOUNDRY_AGENT_NAME"] +dataset_name = os.environ.get("DATASET_NAME", "traces-finetuning-sample") +traces_window_days = int(os.environ.get("FOUNDRY_TRACES_WINDOW_DAYS", "7")) +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run output name so repeated runs do not collide. +# Output names are capped at 50 characters by the service. +run_id = f"{datetime.now(tz=timezone.utc).strftime('%y%m%d%H%M%S')}-{uuid.uuid4().hex[:4]}" +output_name = f"{dataset_name}-{run_id}" +if len(output_name) > 50: + raise ValueError( + f"Output name `{output_name}` exceeds the 50-character service limit. " + f"Lower DATASET_NAME (currently `{dataset_name}`) so that `-` fits within 50 characters." + ) + +# Trace look-back window: now - `traces_window_days` ... now. +end_time = datetime.now(tz=timezone.utc) +start_time = end_time - timedelta(days=traces_window_days) + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + + # ------------------------------------------------------------------ + # 1. Submit a fine-tuning data generation job that reads agent traces. + # ------------------------------------------------------------------ + print( + f"Create a fine-tuning data generation job from traces for agent `{agent_name}` (window: {traces_window_days} day(s))." + ) + job = DataGenerationJob( + inputs=DataGenerationJobInputs( + name=f"traces-finetuning-{run_id}", + scenario=DataGenerationJobScenario.SUPERVISED_FINETUNING, + sources=[ + TracesDataGenerationJobSource( + description="Application Insights conversation traces for the Foundry agent.", + agent_name=agent_name, + start_time=start_time, + end_time=end_time, + ), + ], + options=TracesDataGenerationJobOptions( + # Service requires max_samples to be between 15 and 1000. + max_samples=15, + # Split generated samples 80% training / 20% validation. + train_split=0.8, + ), + output_options=DataGenerationJobOutputOptions(name=output_name), + ), + ) + job = project_client.beta.datasets.create_generation_job(job=job) + print(f"Created data generation job `{job.id}` (status: `{job.status}`).") + + print(f"Poll job `{job.id}` until it reaches a terminal state.", end="", flush=True) + while True: + job = project_client.beta.datasets.get_generation_job(job_id=job.id) + if job.status in TERMINAL_STATUSES: + break + time.sleep(poll_interval_seconds) + print(".", end="", flush=True) + print() + print(f"Final job status: `{job.status}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Job `{job.id}` ended with status `{job.status}`: {message}") + + # ------------------------------------------------------------------ + # 2. Inspect the generated fine-tuning file outputs. + # ------------------------------------------------------------------ + # `train_split=0.8` produces two Azure OpenAI files: a training partition + # and a validation partition. Both are emitted as FileDataGenerationJobOutput + # entries in `job.result.outputs`. + file_outputs = [ + output + for output in ((job.result.outputs if job.result is not None else None) or []) + if isinstance(output, FileDataGenerationJobOutput) + ] + if not file_outputs: + raise RuntimeError(f"Job `{job.id}` did not produce any file outputs.") + + print(f"Generated {len(file_outputs)} fine-tuning file(s):") + for output in file_outputs: + if not output.id: + raise RuntimeError(f"Job `{job.id}` returned a file output without an id.") + # Resolve the Azure OpenAI file to surface its real filename and size. + file_info = openai_client.files.retrieve(file_id=output.id) + print(f" - filename=`{file_info.filename}` id=`{output.id}` bytes={file_info.bytes}") + if job.result is not None and job.result.generated_samples is not None: + print(f"Generated samples: {job.result.generated_samples}") + + # ------------------------------------------------------------------ + # 3. Clean up. + # ------------------------------------------------------------------ + for output in file_outputs: + print(f"Delete the generated Azure OpenAI file `{output.id}`.") + openai_client.files.delete(file_id=output.id) + + print(f"Delete the data generation job `{job.id}`.") + project_client.beta.datasets.delete_generation_job(job_id=job.id) diff --git a/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets.py b/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets.py index 791b33754479..8860575516f2 100644 --- a/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets.py +++ b/sdk/ai/azure-ai-projects/samples/datasets/sample_datasets.py @@ -62,7 +62,6 @@ "or set CONNECTION_NAME explicitly." ) from e - # [START datasets_sample] print( f"Upload a single file and create a new Dataset `{dataset_name}`, version `{dataset_version_1}`, to reference the file." ) @@ -105,4 +104,3 @@ print("Delete all Dataset versions created above:") project_client.datasets.delete(name=dataset_name, version=dataset_version_1) project_client.datasets.delete(name=dataset_name, version=dataset_version_2) - # [END dataset_sample] diff --git a/sdk/ai/azure-ai-projects/samples/deployments/sample_deployments.py b/sdk/ai/azure-ai-projects/samples/deployments/sample_deployments.py index 203015acdad7..2d46858fc7c4 100644 --- a/sdk/ai/azure-ai-projects/samples/deployments/sample_deployments.py +++ b/sdk/ai/azure-ai-projects/samples/deployments/sample_deployments.py @@ -41,7 +41,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): - # [START deployments_sample] print("List all deployments:") for deployment in project_client.deployments.list(): print(deployment) @@ -68,4 +67,3 @@ print(f"Capabilities: {deployment.capabilities}") print(f"SKU: {deployment.sku}") print(f"Connection Name: {deployment.connection_name}") - # [END deployments_sample] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/README.md b/sdk/ai/azure-ai-projects/samples/evaluations/README.md index d601e9e22906..9a3dc1dc6f45 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/README.md +++ b/sdk/ai/azure-ai-projects/samples/evaluations/README.md @@ -80,6 +80,16 @@ These samples require additional setup or Azure services: | [sample_eval_catalog_code_based_evaluators.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_eval_catalog_code_based_evaluators.py) | Custom code-based (inline) evaluators | | [sample_eval_catalog_prompt_based_evaluators.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_eval_catalog_prompt_based_evaluators.py) | Custom prompt-based evaluators | +### Rubric Evaluators + +| Sample | Description | +|--------|-------------| +| [sample_rubric_evaluator_manual.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_manual.py) | Hand-author a rubric evaluator (dimensions, weights, pass threshold) with `create_version`, then use it in an OpenAI eval run | +| [sample_rubric_evaluator_generation_basic.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_basic.py) | Generate an evaluator from a single prompt source, inspect the produced dimensions, and use the auto-saved evaluator in an eval run | +| [sample_rubric_evaluator_generation_all_sources.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_all_sources.py) | Exercise every source type — prompt + agent + dataset in a combined job, plus a separate traces + agent-companion job | +| [sample_rubric_evaluator_generation_iterate.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_iterate.py) | Human-in-the-loop iteration: generate v1, edit dimensions locally, save as v2 with `create_version` | +| [sample_rubric_evaluator_generation_lifecycle.py](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_lifecycle.py) | Full generation-job lifecycle: idempotent `create_generation_job`, polling, list, and delete | + ### Agentic Evaluators Located in the [agentic_evaluators](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators) subfolder: diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_coherence.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_coherence.py index ad2ade399e44..6e7ac2716800 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_coherence.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_coherence.py @@ -68,7 +68,7 @@ def main() -> None: type="azure_ai_evaluator", name="coherence", evaluator_name="builtin.coherence", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, ) ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_fluency.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_fluency.py index bf13efca2392..928982e61741 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_fluency.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_fluency.py @@ -68,7 +68,7 @@ def main() -> None: type="azure_ai_evaluator", name="fluency", evaluator_name="builtin.fluency", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, ) ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_generic_agentic_evaluator/sample_generic_agentic_evaluator.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_generic_agentic_evaluator/sample_generic_agentic_evaluator.py index 1b2afc8d6705..33f1f07d81a8 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_generic_agentic_evaluator/sample_generic_agentic_evaluator.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_generic_agentic_evaluator/sample_generic_agentic_evaluator.py @@ -37,7 +37,7 @@ def _get_evaluator_initialization_parameters(evaluator_name: str) -> dict[str, s if evaluator_name == "task_navigation_efficiency": return {"matching_mode": "exact_match"} # Can be "exact_match", "in_order_match", or "any_order_match" model_deployment_name = os.environ.get("FOUNDRY_MODEL_NAME", "") # Sample : gpt-4o-mini - return {"deployment_name": model_deployment_name} + return {"model": model_deployment_name} def _get_evaluation_contents() -> list[SourceFileContentContent]: diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_intent_resolution.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_intent_resolution.py index 19a3b639976e..16a2c43e3914 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_intent_resolution.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_intent_resolution.py @@ -73,7 +73,7 @@ def main() -> None: type="azure_ai_evaluator", name="intent_resolution", evaluator_name="builtin.intent_resolution", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={ "query": "{{item.query}}", "response": "{{item.response}}", diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_relevance.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_relevance.py index 2b1563cfa9b2..552b94ba241a 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_relevance.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_relevance.py @@ -72,7 +72,7 @@ def main() -> None: type="azure_ai_evaluator", name="relevance", evaluator_name="builtin.relevance", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, ) ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_response_completeness.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_response_completeness.py index 119cd795206d..e90c950c1192 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_response_completeness.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_response_completeness.py @@ -70,7 +70,7 @@ def main() -> None: type="azure_ai_evaluator", name="response_completeness", evaluator_name="builtin.response_completeness", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"ground_truth": "{{item.ground_truth}}", "response": "{{item.response}}"}, ) ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_accuracy.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_accuracy.py index 62f57a6ddbf9..4398cc394d0d 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_accuracy.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_accuracy.py @@ -75,7 +75,7 @@ def main() -> None: type="azure_ai_evaluator", name="tool_call_accuracy", evaluator_name="builtin.tool_call_accuracy", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={ "query": "{{item.query}}", "tool_definitions": "{{item.tool_definitions}}", diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_success.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_success.py index 0517a9da2152..00e87cd64294 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_success.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_call_success.py @@ -73,7 +73,7 @@ def main() -> None: type="azure_ai_evaluator", name="tool_call_success", evaluator_name="builtin.tool_call_success", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"tool_definitions": "{{item.tool_definitions}}", "response": "{{item.response}}"}, ) ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_input_accuracy.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_input_accuracy.py index 6a78a92ad79e..685c491f1339 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_input_accuracy.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_input_accuracy.py @@ -74,7 +74,7 @@ def main() -> None: type="azure_ai_evaluator", name="tool_input_accuracy", evaluator_name="builtin.tool_input_accuracy", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={ "query": "{{item.query}}", "response": "{{item.response}}", diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_output_utilization.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_output_utilization.py index 4d2d84fa52a0..2dd3f0bdbcdc 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_output_utilization.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_output_utilization.py @@ -72,7 +72,7 @@ def main() -> None: type="azure_ai_evaluator", name="tool_output_utilization", evaluator_name="builtin.tool_output_utilization", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={ "query": "{{item.query}}", "response": "{{item.response}}", diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_selection.py b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_selection.py index e4b40fa577a5..ff7806784dec 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_selection.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/agentic_evaluators/sample_tool_selection.py @@ -75,7 +75,7 @@ def main() -> None: type="azure_ai_evaluator", name="tool_selection", evaluator_name="builtin.tool_selection", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={ "query": "{{item.query}}", "response": "{{item.response}}", diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/data_folder/sample_data_multiturn_conversations.jsonl b/sdk/ai/azure-ai-projects/samples/evaluations/data_folder/sample_data_multiturn_conversations.jsonl new file mode 100644 index 000000000000..7f1aa206e38d --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/data_folder/sample_data_multiturn_conversations.jsonl @@ -0,0 +1,3 @@ +{"messages": [{"role": "system", "content": "You are a helpful travel assistant."}, {"role": "user", "content": "I need to book a flight to Paris."}, {"role": "assistant", "content": "I'd be happy to help you book a flight to Paris. What dates are you looking to travel?"}, {"role": "user", "content": "Next Friday, returning Sunday."}, {"role": "assistant", "content": "I found several options for flights departing next Friday and returning Sunday. The best value is a direct flight on Air France for $450 round trip. Would you like me to book this for you?"}]} +{"messages": [{"role": "user", "content": "What's the weather in Paris?"}, {"role": "assistant", "content": null, "tool_calls": [{"id": "call_123", "type": "function", "function": {"name": "get_weather", "arguments": "{\"location\": \"Paris\"}"}}]}, {"role": "tool", "tool_call_id": "call_123", "content": "{\"temperature\": 18, \"condition\": \"sunny\"}"}, {"role": "assistant", "content": "The weather in Paris is currently sunny with a temperature of 18\u00b0C (64\u00b0F)."}], "tool_definitions": [{"name": "get_weather", "description": "Get current weather for a location", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}}}]} +{"messages": [{"role": "system", "content": "You are a customer service agent for a software company."}, {"role": "user", "content": "I can't log into my account. I've tried resetting my password but the email never arrives."}, {"role": "assistant", "content": "I'm sorry to hear you're having trouble logging in. Let me help you with that. Can you confirm the email address associated with your account?"}, {"role": "user", "content": "It's john.doe@example.com"}, {"role": "assistant", "content": "Thank you. I can see that the reset emails are being sent to john.doe@example.com but they appear to be bouncing. It looks like there may be a typo in the email on file. Would you like me to update it?"}, {"role": "user", "content": "Oh yes, it should be john.doe@example.org"}, {"role": "assistant", "content": "I've updated your email to john.doe@example.org and sent a new password reset link. You should receive it within the next few minutes. Is there anything else I can help you with?"}]} diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/data_folder/sample_data_simulation_scenarios.jsonl b/sdk/ai/azure-ai-projects/samples/evaluations/data_folder/sample_data_simulation_scenarios.jsonl new file mode 100644 index 000000000000..a5ccbced6e9d --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/data_folder/sample_data_simulation_scenarios.jsonl @@ -0,0 +1,3 @@ +{"id": "scenario-1-greeting", "test_case_description": "User starts with a casual greeting; agent should respond warmly and offer help.", "desired_num_turns": 3} +{"id": "scenario-2-weather-followup", "test_case_description": "User asks about the weather in a major city, then asks a follow-up about whether to bring an umbrella.", "desired_num_turns": 4} +{"id": "scenario-3-store-hours", "test_case_description": "User asks if a store is open, then progressively narrows down to curbside-pickup hours, then places an order.", "desired_num_turns": 5} diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_evaluation.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_evaluation.py index 4882737ce719..5a930105fb95 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_evaluation.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_evaluation.py @@ -48,7 +48,6 @@ endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] model_deployment_name = os.environ.get("FOUNDRY_MODEL_NAME", "") # Sample : gpt-4o-mini -# [START agent_evaluation_basic] with ( DefaultAzureCredential() as credential, AIProjectClient(endpoint=endpoint, credential=credential) as project_client, @@ -82,14 +81,14 @@ type="azure_ai_evaluator", name="fluency", evaluator_name="builtin.fluency", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"query": "{{item.query}}", "response": "{{sample.output_text}}"}, ), TestingCriterionAzureAIEvaluator( type="azure_ai_evaluator", name="task_adherence", evaluator_name="builtin.task_adherence", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, data_mapping={"query": "{{item.query}}", "response": "{{sample.output_items}}"}, ), ] @@ -126,7 +125,6 @@ eval_id=eval_object.id, name=f"Evaluation Run for Agent {agent.name}", data_source=data_source # type: ignore ) print(f"Evaluation run created (id: {agent_eval_run.id})") - # [END agent_evaluation_basic] while agent_eval_run.status not in ["completed", "failed"]: agent_eval_run = openai_client.evals.runs.retrieve(run_id=agent_eval_run.id, eval_id=eval_object.id) diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_response_evaluation.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_response_evaluation.py index 8fadf705b2b4..040e321ef498 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_response_evaluation.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_agent_response_evaluation.py @@ -77,7 +77,8 @@ data_source_config = AzureAIDataSourceConfig(type="azure_ai_source", scenario="responses") testing_criteria = [ TestingCriterionAzureAIEvaluator( - type="azure_ai_evaluator", name="violence_detection", evaluator_name="builtin.violence" + type="azure_ai_evaluator", name="violence_detection", evaluator_name="builtin.violence", + data_mapping={"query": "{{item.query}}", "response": "{{sample.output_text}}"} ) ] eval_object = openai_client.evals.create( diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_eval_catalog_prompt_based_evaluators.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_eval_catalog_prompt_based_evaluators.py index 8b217aab6b95..77efc2d9c11e 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_eval_catalog_prompt_based_evaluators.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_eval_catalog_prompt_based_evaluators.py @@ -180,7 +180,7 @@ "response": "{{item.response}}", "ground_truth": "{{item.ground_truth}}", }, - initialization_parameters={"deployment_name": f"{model_deployment_name}", "threshold": 3}, + initialization_parameters={"model": f"{model_deployment_name}", "threshold": 3}, ) ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_ai_assisted.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_ai_assisted.py index c15161a7680c..0e0fcb9f863c 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_ai_assisted.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_ai_assisted.py @@ -67,7 +67,7 @@ name="Similarity", evaluator_name="builtin.similarity", data_mapping={"response": "{{item.response}}", "ground_truth": "{{item.ground_truth}}"}, - initialization_parameters={"deployment_name": f"{model_deployment_name}", "threshold": 3}, + initialization_parameters={"model": f"{model_deployment_name}", "threshold": 3}, ), TestingCriterionAzureAIEvaluator( type="azure_ai_evaluator", diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_csv.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_csv.py index ef93427ddf2b..d9181d4be836 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_csv.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_csv.py @@ -94,7 +94,7 @@ name="violence", evaluator_name="builtin.violence", data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, ), TestingCriterionAzureAIEvaluator(type="azure_ai_evaluator", name="f1", evaluator_name="builtin.f1_score"), TestingCriterionAzureAIEvaluator( @@ -102,7 +102,7 @@ name="coherence", evaluator_name="builtin.coherence", data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, ), ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_dataset_id.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_dataset_id.py index c2ceaa15d807..93798bb84eba 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_dataset_id.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_dataset_id.py @@ -88,14 +88,14 @@ name="violence", evaluator_name="builtin.violence", data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, ), TestingCriterionAzureAIEvaluator(type="azure_ai_evaluator", name="f1", evaluator_name="builtin.f1_score"), TestingCriterionAzureAIEvaluator( type="azure_ai_evaluator", name="coherence", evaluator_name="builtin.coherence", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, ), ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data.py index 1cc7438f658b..a4b47d1e1876 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data.py @@ -77,14 +77,20 @@ name="violence", evaluator_name="builtin.violence", data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="f1", + evaluator_name="builtin.f1_score", + data_mapping={"query": "{{item.query}}", "response": "{{item.response}}", "ground_truth": "{{item.ground_truth}}"}, ), - TestingCriterionAzureAIEvaluator(type="azure_ai_evaluator", name="f1", evaluator_name="builtin.f1_score"), TestingCriterionAzureAIEvaluator( type="azure_ai_evaluator", name="coherence", evaluator_name="builtin.coherence", - initialization_parameters={"deployment_name": f"{model_deployment_name}"}, + initialization_parameters={"model": f"{model_deployment_name}"}, + data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, ), ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data_oai.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data_oai.py index fdac39982367..9e496cc6524f 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data_oai.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_inline_data_oai.py @@ -66,14 +66,14 @@ "name": "violence", "evaluator_name": "builtin.violence", "data_mapping": {"query": "{{item.query}}", "response": "{{item.response}}"}, - "initialization_parameters": {"deployment_name": f"{model_deployment_name}"}, + "initialization_parameters": {"model": f"{model_deployment_name}"}, }, {"type": "azure_ai_evaluator", "name": "f1", "evaluator_name": "builtin.f1_score"}, { "type": "azure_ai_evaluator", "name": "coherence", "evaluator_name": "builtin.coherence", - "initialization_parameters": {"deployment_name": f"{model_deployment_name}"}, + "initialization_parameters": {"model": f"{model_deployment_name}"}, }, ] diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_traces.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_traces.py index dd2271d4d6b7..a5e88ab53301 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_traces.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_builtin_with_traces.py @@ -7,12 +7,21 @@ """ DESCRIPTION: Given an AIProjectClient, this sample demonstrates how to run Azure AI Evaluations - against agent traces collected in Azure Application Insights. The sample fetches - trace IDs for a given agent and time range, creates an evaluation group configured - for trace analysis, and monitors the evaluation run until it completes. + against agent traces collected in Azure Application Insights. + + Supports three modes: + - Default mode (no flags): Queries Application Insights client-side for trace IDs + using the AGENT_ID environment variable, then passes them to the eval service. + - Agent ID mode (--agent-id): Passes the agent ID directly to the eval service, + which resolves traces server-side from Application Insights. + - Trace ID mode (--trace-ids): Passes explicit trace IDs to the eval service. USAGE: python sample_evaluations_builtin_with_traces.py + python sample_evaluations_builtin_with_traces.py --agent-id "my-agent:1" + python sample_evaluations_builtin_with_traces.py --trace-ids abc123 def456 + python sample_evaluations_builtin_with_traces.py --agent-id "my-agent:1" --lookback-hours 48 --max-traces 20 + python sample_evaluations_builtin_with_traces.py --no-cleanup Before running the sample: @@ -21,7 +30,8 @@ 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. It has the form: https://.services.ai.azure.com/api/projects/. - 2) APPINSIGHTS_RESOURCE_ID - Required. The Azure Application Insights resource ID that stores agent traces. + 2) APPINSIGHTS_RESOURCE_ID - Required (for default mode). The Azure Application Insights resource ID that stores + agent traces. Not needed when using --agent-id or --trace-ids. It has the form: /subscriptions//resourceGroups//providers/Microsoft.Insights/components/. 3) AGENT_ID - Required. The agent identifier emitted by the Azure tracing integration, used to filter traces. 4) FOUNDRY_MODEL_NAME - Required. The Azure OpenAI deployment name to use with the built-in evaluators. @@ -29,19 +39,18 @@ Defaults to 1. """ +import argparse import os import time from datetime import datetime, timedelta, timezone from pprint import pprint -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional from dotenv import load_dotenv from azure.identity import DefaultAzureCredential from azure.monitor.query import LogsQueryClient, LogsQueryStatus from azure.ai.projects import AIProjectClient from azure.ai.projects.models import ( - AzureAIDataSourceConfig, TestingCriterionAzureAIEvaluator, - TracesPreviewEvalRunDataSource, ) load_dotenv() @@ -53,7 +62,7 @@ ] # Sample : /subscriptions//resourceGroups//providers/Microsoft.Insights/components/ agent_id = os.environ["AGENT_ID"] model_deployment_name = os.environ["FOUNDRY_MODEL_NAME"] -trace_query_hours = int(os.environ.get("TRACE_LOOKBACK_HOURS", "1")) +default_lookback_hours = int(os.environ.get("TRACE_LOOKBACK_HOURS", "1")) def _build_evaluator_config(name: str, evaluator_name: str) -> TestingCriterionAzureAIEvaluator: @@ -63,9 +72,9 @@ def _build_evaluator_config(name: str, evaluator_name: str) -> TestingCriterionA name=name, evaluator_name=evaluator_name, data_mapping={ - "query": "{{query}}", - "response": "{{response}}", - "tool_definitions": "{{tool_definitions}}", + "query": "{{sample.query}}", + "response": "{{sample.response}}", + "tool_definitions": "{{sample.tool_definitions}}", }, initialization_parameters={ "deployment_name": model_deployment_name, @@ -121,92 +130,133 @@ def get_trace_ids( return [] -def main() -> None: - end_time = datetime.now(tz=timezone.utc) - start_time = end_time - timedelta(hours=trace_query_hours) +def main() -> None: # pylint: disable=too-many-statements + parser = argparse.ArgumentParser(description="Run Azure AI trace evaluations against agent traces.") + mode = parser.add_mutually_exclusive_group() + mode.add_argument("--agent-id", default=None, help="Agent ID for server-side trace resolution") + mode.add_argument("--trace-ids", nargs="+", default=None, help="Explicit trace IDs to evaluate") + parser.add_argument("--lookback-hours", type=int, default=None, help="Lookback window in hours") + parser.add_argument("--max-traces", type=int, default=50, help="Max traces in agent-id mode (default: 50)") + parser.add_argument("--no-cleanup", action="store_true", help="Keep eval group after run") + args = parser.parse_args() + + lookback_hours = args.lookback_hours or default_lookback_hours + trace_ids: Optional[List[str]] = None + agent_id_for_server: Optional[str] = None + metadata: Dict[str, str] = {} + + if args.agent_id: + agent_id_for_server = args.agent_id + print("Mode: Server-side agent ID resolution") + print(f"Agent ID: {args.agent_id}") + print(f"Lookback: {lookback_hours}h, Max traces: {args.max_traces}") + metadata["agent_id"] = args.agent_id + + elif args.trace_ids: + trace_ids = list(args.trace_ids) + print(f"Mode: Explicit trace IDs ({len(trace_ids)} provided)") + + else: + end_time = datetime.now(tz=timezone.utc) + start_time = end_time - timedelta(hours=lookback_hours) - print("Querying Application Insights for trace identifiers...") - print(f"Agent ID: {agent_id}") - print(f"Time range: {start_time.isoformat()} to {end_time.isoformat()}") + print("Querying Application Insights for trace identifiers...") + print(f"Agent ID: {agent_id}") + print(f"Time range: {start_time.isoformat()} to {end_time.isoformat()}") - trace_ids = get_trace_ids(appinsights_resource_id, agent_id, start_time, end_time) + trace_ids = get_trace_ids(appinsights_resource_id, agent_id, start_time, end_time) - if not trace_ids: - print("No trace IDs found for the provided agent and time window.") - return + if not trace_ids: + print("No trace IDs found for the provided agent and time window.") + return - print(f"\nFound {len(trace_ids)} trace IDs:") - for trace_id in trace_ids: - print(f" - {trace_id}") + print(f"\nFound {len(trace_ids)} trace IDs:") + for tid in trace_ids: + print(f" - {tid}") + + metadata["agent_id"] = agent_id + metadata["start_time"] = start_time.isoformat() + metadata["end_time"] = end_time.isoformat() with DefaultAzureCredential() as credential: with AIProjectClient(endpoint=endpoint, credential=credential) as project_client: client = project_client.get_openai_client() - data_source_config = AzureAIDataSourceConfig( - type="azure_ai_source", - scenario="traces", - ) - testing_criteria = [ - _build_evaluator_config( - name="intent_resolution", - evaluator_name="builtin.intent_resolution", - ), - _build_evaluator_config( - name="task_adherence", - evaluator_name="builtin.task_adherence", - ), - ] - - print("\nCreating evaluation") - eval_object = client.evals.create( - name="agent_trace_eval_group", - data_source_config=data_source_config, - testing_criteria=testing_criteria, - ) - print(f"Evaluation created (id: {eval_object.id}, name: {eval_object.name})") - - print("\nGet Evaluation by Id") - eval_object_response = client.evals.retrieve(eval_object.id) - print("Evaluation Response:") - pprint(eval_object_response) - - print("\nCreating Eval Run with trace IDs") - run_name = f"agent_trace_eval_{datetime.now().strftime('%Y%m%d_%H%M%S')}" - data_source = TracesPreviewEvalRunDataSource( - type="azure_ai_traces_preview", - trace_ids=trace_ids, - lookback_hours=trace_query_hours, - ) - eval_run_object = client.evals.runs.create( - eval_id=eval_object.id, - name=run_name, - metadata={ - "agent_id": agent_id, - "start_time": start_time.isoformat(), - "end_time": end_time.isoformat(), - }, - data_source=data_source, - ) - print("Eval Run created") - pprint(eval_run_object) - - print("\nMonitoring Eval Run status...") - while True: - run = client.evals.runs.retrieve(run_id=eval_run_object.id, eval_id=eval_object.id) - print(f"Status: {run.status}") - - if run.status in {"completed", "failed", "canceled"}: - print("\nEval Run finished!") - print("Final Eval Run Response:") - pprint(run) - break - - time.sleep(5) - print("Waiting for eval run to complete...") - - client.evals.delete(eval_id=eval_object.id) - print("Evaluation deleted") + data_source_config = { + "type": "azure_ai_source", + "scenario": "traces", + } + + testing_criteria = [ + _build_evaluator_config( + name="intent_resolution", + evaluator_name="builtin.intent_resolution", + ), + _build_evaluator_config( + name="task_adherence", + evaluator_name="builtin.task_adherence", + ), + ] + + print("\nCreating evaluation") + eval_object = client.evals.create( + name="agent_trace_eval_group", + data_source_config=data_source_config, # type: ignore + testing_criteria=testing_criteria, # type: ignore + ) + print(f"Evaluation created (id: {eval_object.id}, name: {eval_object.name})") + + print("\nGet Evaluation by Id") + eval_object_response = client.evals.retrieve(eval_object.id) + print("Evaluation Response:") + pprint(eval_object_response) + + # Build data source based on mode + if agent_id_for_server: + data_source: Dict[str, Any] = { + "type": "azure_ai_traces", + "agent_id": agent_id_for_server, + "lookback_hours": lookback_hours, + "max_traces": args.max_traces, + } + else: + assert trace_ids is not None + data_source = { + "type": "azure_ai_traces", + "trace_ids": trace_ids, + "lookback_hours": lookback_hours, + } + + print("\nCreating Eval Run") + run_name = f"agent_trace_eval_{datetime.now().strftime('%Y%m%d_%H%M%S')}" + eval_run_object = client.evals.runs.create( + eval_id=eval_object.id, + name=run_name, + metadata=metadata if metadata else None, + data_source=data_source, # type: ignore + ) + print("Eval Run created") + pprint(eval_run_object) + + print("\nMonitoring Eval Run status...") + while True: + run = client.evals.runs.retrieve(run_id=eval_run_object.id, eval_id=eval_object.id) + print(f"Status: {run.status}") + + if run.status in {"completed", "failed", "canceled"}: + print("\nEval Run finished!") + print("Final Eval Run Response:") + pprint(run) + break + + time.sleep(5) + print("Waiting for eval run to complete...") + + if not args.no_cleanup: + client.evals.delete(eval_id=eval_object.id) + print("Evaluation deleted") + else: + print(f"Skipping cleanup (--no-cleanup). Eval ID: {eval_object.id}") if __name__ == "__main__": diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio.py index 7583f1e8636e..165bd0f43929 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio.py @@ -26,13 +26,15 @@ 3) AZURE_AI_MODEL_DEPLOYMENT_NAME_FOR_AUDIO - Required. The name of the model deployment for audio to use for evaluation, recommend to use "gpt-4o-audio-preview" """ -import os import base64 - -from azure.identity import DefaultAzureCredential -from azure.ai.projects import AIProjectClient +import os import time from pprint import pprint + +from dotenv import load_dotenv +from azure.ai.projects import AIProjectClient +from azure.identity import DefaultAzureCredential +from openai.types.eval_create_params import DataSourceConfigCustom from openai.types.evals.create_eval_completions_run_data_source_param import ( CreateEvalCompletionsRunDataSourceParam, SourceFileContent, @@ -41,8 +43,6 @@ InputMessagesTemplateTemplateEvalItem, ) from openai.types.responses import EasyInputMessageParam, ResponseInputAudioParam -from openai.types.eval_create_params import DataSourceConfigCustom -from dotenv import load_dotenv load_dotenv() file_path = os.path.abspath(__file__) @@ -54,7 +54,13 @@ def audio_to_base64(audio_path: str) -> str: - """Read an audio file and return its base64-encoded content.""" + """Read an audio file and return its base64-encoded content. + + :param audio_path: Absolute path to the input audio file. + :type audio_path: str + :return: Base64-encoded audio data. + :rtype: str + """ with open(audio_path, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") @@ -183,7 +189,7 @@ def audio_to_base64(audio_path: str) -> str: while True: run = client.evals.runs.retrieve(run_id=eval_run_response.id, eval_id=eval_object.id) - if run.status == "completed" or run.status == "failed": + if run.status in {"completed", "failed"}: output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) pprint(output_items) print(f"Eval Run Report URL: {run.report_url}") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio_model_target.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio_model_target.py index 5c3c4ae51f78..75eb7b97f566 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio_model_target.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_audio_model_target.py @@ -26,13 +26,15 @@ 3) AZURE_AI_MODEL_DEPLOYMENT_NAME_FOR_AUDIO - Required. The name of the model deployment for audio to use for evaluation, recommend to use "gpt-4o-audio-preview" """ -import os import base64 - -from azure.identity import DefaultAzureCredential -from azure.ai.projects import AIProjectClient +import os import time from pprint import pprint + +from dotenv import load_dotenv +from azure.ai.projects import AIProjectClient +from azure.identity import DefaultAzureCredential +from openai.types.eval_create_params import DataSourceConfigCustom from openai.types.evals.create_eval_completions_run_data_source_param import ( SourceFileContent, SourceFileContentContent, @@ -40,8 +42,6 @@ InputMessagesTemplateTemplateEvalItem, ) from openai.types.responses import EasyInputMessageParam, ResponseInputAudioParam -from openai.types.eval_create_params import DataSourceConfigCustom -from dotenv import load_dotenv load_dotenv() file_path = os.path.abspath(__file__) @@ -53,7 +53,13 @@ def audio_to_base64(audio_path: str) -> str: - """Read an audio file and return its base64-encoded content.""" + """Read an audio file and return its base64-encoded content. + + :param audio_path: Absolute path to the input audio file. + :type audio_path: str + :return: Base64-encoded audio data. + :rtype: str + """ with open(audio_path, "rb") as f: return base64.b64encode(f.read()).decode("utf-8") @@ -188,7 +194,7 @@ def audio_to_base64(audio_path: str) -> str: while True: run = client.evals.runs.retrieve(run_id=eval_run_response.id, eval_id=eval_object.id) - if run.status == "completed" or run.status == "failed": + if run.status in {"completed", "failed"}: output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) pprint(output_items) print(f"Eval Run Report URL: {run.report_url}") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_image_model_target.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_image_model_target.py index 88920549113d..01a22ccfe588 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_image_model_target.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_evaluations_score_model_grader_with_image_model_target.py @@ -23,15 +23,17 @@ 2) AZURE_AI_MODEL_DEPLOYMENT_NAME - Required. The name of the model deployment to use for evaluation. """ -import os import base64 -from PIL import Image +import os +import time from io import BytesIO +from pprint import pprint -from azure.identity import DefaultAzureCredential +from PIL import Image +from dotenv import load_dotenv from azure.ai.projects import AIProjectClient -import time -from pprint import pprint +from azure.identity import DefaultAzureCredential +from openai.types.eval_create_params import DataSourceConfigCustom from openai.types.evals.create_eval_completions_run_data_source_param import ( SourceFileContent, SourceFileContentContent, @@ -40,8 +42,6 @@ InputMessagesTemplateTemplateEvalItemContentInputImage, ) from openai.types.responses import EasyInputMessageParam -from openai.types.eval_create_params import DataSourceConfigCustom -from dotenv import load_dotenv load_dotenv() file_path = os.path.abspath(__file__) @@ -51,8 +51,8 @@ model_deployment_name = os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"] -def image_to_data_uri(image_path: str) -> str: - with Image.open(image_path) as img: +def image_to_data_uri(image_file_path: str) -> str: + with Image.open(image_file_path) as img: buffered = BytesIO() img.save(buffered, format=img.format or "PNG") img_str = base64.b64encode(buffered.getvalue()).decode() @@ -186,7 +186,7 @@ def image_to_data_uri(image_path: str) -> str: while True: run = client.evals.runs.retrieve(run_id=eval_run_response.id, eval_id=eval_object.id) - if run.status == "completed" or run.status == "failed": + if run.status in {"completed", "failed"}: output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) pprint(output_items) print(f"Eval Run Report URL: {run.report_url}") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_model_evaluation_instant_model.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_model_evaluation_instant_model.py new file mode 100644 index 000000000000..1517b05eab62 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_model_evaluation_instant_model.py @@ -0,0 +1,129 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +""" +DESCRIPTION: + This sample demonstrates how to create and run an evaluation for an Azure AI model + using the synchronous AIProjectClient. + + The OpenAI compatible Evals calls in this sample are made using + the OpenAI client from the `openai` package. See https://platform.openai.com/docs/api-reference + for more information. + +USAGE: + python sample_model_evaluation.py + + Before running the sample: + + pip install "azure-ai-projects>=2.0.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_INSTANT_MODEL_NAME - The deployment name of the AI model, as found under the "Name" column in + the "Models + endpoints" tab in your Microsoft Foundry project. +""" + +import os +import time +from pprint import pprint +from typing import Union +from dotenv import load_dotenv +from openai.types.evals.create_eval_completions_run_data_source_param import SourceFileContent, SourceFileContentContent +from openai.types.eval_create_params import DataSourceConfigCustom +from openai.types.evals.run_create_response import RunCreateResponse +from openai.types.evals.run_retrieve_response import RunRetrieveResponse +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + AzureAIModelTargetParam, + TestingCriterionAzureAIEvaluator, + ModelSamplingConfigParam, + TargetCompletionEvalRunDataSource, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + data_source_config = DataSourceConfigCustom( + type="custom", + item_schema={"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}, + include_sample_schema=True, + ) + # Notes: for data_mapping: + # {{sample.output_text}} is the string output of the provide model target for the given input in {{item.query}} + testing_criteria = [ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="violence_detection", + evaluator_name="builtin.violence", + data_mapping={"query": "{{item.query}}", "response": "{{sample.output_text}}"}, + ) + ] + eval_object = openai_client.evals.create( + name="Model Evaluation", + data_source_config=data_source_config, + testing_criteria=testing_criteria, + ) + print(f"Evaluation created (id: {eval_object.id}, name: {eval_object.name})") + + model = os.environ["FOUNDRY_INSTANT_MODEL_NAME"] + data_source = TargetCompletionEvalRunDataSource( + type="azure_ai_target_completions", + source=SourceFileContent( + type="file_content", + content=[ + SourceFileContentContent(item={"query": "What is the capital of France?"}), + SourceFileContentContent(item={"query": "How do I reverse a string in Python?"}), + ], + ), + input_messages={ + "type": "template", # type: ignore + "template": [ + {"type": "message", "role": "user", "content": {"type": "input_text", "text": "{{item.query}}"}} + ], + }, + target=AzureAIModelTargetParam( + type="azure_ai_model", + model=model, + sampling_params=ModelSamplingConfigParam( # Note: model sampling parameters are optional and can differ per model + top_p=1.0, + max_completion_tokens=2048, + ), + ), + ) + + agent_eval_run: Union[RunCreateResponse, RunRetrieveResponse] = openai_client.evals.runs.create( + eval_id=eval_object.id, name=f"Evaluation Run for Model {model}", data_source=data_source # type: ignore + ) + print(f"Evaluation run created (id: {agent_eval_run.id})") + + while agent_eval_run.status not in ["completed", "failed"]: + agent_eval_run = openai_client.evals.runs.retrieve(run_id=agent_eval_run.id, eval_id=eval_object.id) + print(f"Waiting for eval run to complete... current status: {agent_eval_run.status}") + time.sleep(5) + + if agent_eval_run.status == "completed": + print("\n✓ Evaluation run completed successfully!") + print(f"Result Counts: {agent_eval_run.result_counts}") + + output_items = list( + openai_client.evals.runs.output_items.list(run_id=agent_eval_run.id, eval_id=eval_object.id) + ) + print(f"\nOUTPUT ITEMS (Total: {len(output_items)})") + print(f"{'-'*60}") + pprint(output_items) + print(f"{'-'*60}") + else: + print("\n✗ Evaluation run failed.") + + openai_client.evals.delete(eval_id=eval_object.id) + print("Evaluation deleted") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_conversation_evaluation.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_conversation_evaluation.py new file mode 100644 index 000000000000..375478f59768 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_conversation_evaluation.py @@ -0,0 +1,176 @@ +# 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 create and run a + multi-turn conversation evaluation using the synchronous `openai.evals.*` + methods. Multi-turn evaluations assess complete conversations—including + tool-calling exchanges—using conversation-level metrics such as customer + satisfaction, task completion, coherence, and groundedness. + + This sample uses a JSONL dataset where each row contains a ``messages`` + array (and optional ``tool_definitions``). It shows how to: + - Define a ``custom`` data source config with the conversation schema. + - Select conversation-level evaluators with ``{{item.messages}}`` mapping. + - Upload conversation data, create an evaluation, and run it. + - Poll for completion and print results. + +USAGE: + python sample_multiturn_conversation_evaluation.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" 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. It has the form: https://.services.ai.azure.com/api/projects/. + 2) FOUNDRY_MODEL_NAME - Required. The name of the model deployment to use for AI-assisted evaluators. +""" + +import os +import time +from pprint import pprint +from dotenv import load_dotenv +from openai.types.evals.create_eval_jsonl_run_data_source_param import ( + CreateEvalJSONLRunDataSourceParam, + SourceFileID, +) +from openai.types.eval_create_params import DataSourceConfigCustom +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import TestingCriterionAzureAIEvaluator + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_deployment_name = os.environ["FOUNDRY_MODEL_NAME"] + +# Path to the multi-turn conversation data file +script_dir = os.path.dirname(os.path.abspath(__file__)) +data_folder = os.environ.get("DATA_FOLDER", os.path.join(script_dir, "data_folder")) +data_file = os.path.join(data_folder, "sample_data_multiturn_conversations.jsonl") + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as client, +): + # Define the data source config for multi-turn conversations. + # The item_schema declares the "messages" array and optional "tool_definitions". + # Set include_sample_schema to False since conversation evaluators use + # {{item.messages}} mapping rather than per-turn sample fields. + data_source_config = DataSourceConfigCustom( + type="custom", + item_schema={ + "type": "object", + "properties": { + "messages": {"type": "array"}, + "tool_definitions": {"type": "array"}, + }, + "required": ["messages"], + }, + include_sample_schema=False, + ) + + # Define conversation-level evaluators. + # All evaluators map to {{item.messages}} to assess the full conversation. + testing_criteria = [ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="customer_satisfaction", + evaluator_name="builtin.customer_satisfaction", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="task_completion", + evaluator_name="builtin.task_completion", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="conversation_coherence", + evaluator_name="builtin.coherence", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="groundedness", + evaluator_name="builtin.groundedness", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + ] + + print("Creating multi-turn conversation evaluation") + eval_object = client.evals.create( + name="Multi-turn Conversation Evaluation", + data_source_config=data_source_config, + testing_criteria=testing_criteria, + ) + print(f"Evaluation created (id: {eval_object.id})") + + # Upload the conversation dataset + try: + dataset = project_client.datasets.upload_file( + name="multiturn-conversation-data", + version="1", + file_path=data_file, + ) + assert dataset.id is not None, "Dataset upload returned no ID" + data_id: str = dataset.id + print(f"Dataset uploaded (id: {data_id})") + except Exception: + # Dataset already exists — use the existing URI + account = endpoint.split("/")[2].split(".")[0] + project = endpoint.rstrip("/").split("/")[-1] + data_id = f"azureai://accounts/{account}/projects/{project}/data/multiturn-conversation-data/versions/1" + print(f"Using existing dataset (id: {data_id})") + + # Create a run with evaluation_level set to "conversation" + # so evaluators score each conversation as a whole. + eval_run = client.evals.runs.create( + eval_id=eval_object.id, + name="multiturn-conversation-run", + data_source=CreateEvalJSONLRunDataSourceParam( + type="jsonl", + source=SourceFileID( + type="file_id", + id=data_id, + ), + ), + extra_body={"evaluation_level": "conversation"}, + ) + print(f"Evaluation run created (id: {eval_run.id})") + + while True: + run = client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + if run.status in ("completed", "failed"): + break + print(f"Waiting for eval run to complete... current status: {run.status}") + time.sleep(5) + + if run.status == "completed": + print("\n✓ Evaluation run completed successfully!") + print(f"Result Counts: {run.result_counts}") + + output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) + print(f"\nOUTPUT ITEMS (Total: {len(output_items)})") + print(f"{'-'*60}") + pprint(output_items) + print(f"{'-'*60}") + + print(f"\nEval Run Report URL: {run.report_url}") + else: + print(f"\n✗ Evaluation run failed: {run.error}") + + client.evals.delete(eval_id=eval_object.id) + print("Evaluation deleted") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_conversation_simulation.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_conversation_simulation.py new file mode 100644 index 000000000000..6dd7db32cd9f --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_conversation_simulation.py @@ -0,0 +1,212 @@ +# 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 run a conversation + simulation evaluation against a Foundry agent. The service generates multi-turn + conversations by simulating a user interacting with your agent based on seed + scenarios, then evaluates the generated conversations with conversation-level + metrics. + + This is Scenario 4 of multi-turn evaluations: you provide seed scenarios + (each describing a test case), and the service generates full conversations + by replaying simulated user turns against your agent. The generated + conversations are then scored by conversation-level evaluators. + + Key concepts: + - data_source type is "azure_ai_target_completions" with + item_generation_params.type = "conversation_gen_preview" + - num_conversations is per seed scenario (e.g., 2 conversations × 3 scenarios = 6 total) + - max_turns controls the maximum exchanges per conversation + - The seed scenarios source is at the data_source root level + +USAGE: + python sample_multiturn_conversation_simulation.py + + Before running the sample: + + pip install "azure-ai-projects>=2.0.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint. + 2) FOUNDRY_MODEL_NAME - Required. The model deployment name for the simulator + and AI-assisted evaluators. + 3) FOUNDRY_AGENT_NAME - Required. The name of the Foundry agent to simulate against. +""" + +import os +import time +from pprint import pprint +from dotenv import load_dotenv +from openai.types.eval_create_params import DataSourceConfigCustom +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import TestingCriterionAzureAIEvaluator, PromptAgentDefinition + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_deployment_name = os.environ["FOUNDRY_MODEL_NAME"] +agent_name = os.environ.get("FOUNDRY_AGENT_NAME", "") + +# Path to the simulation scenarios data file +script_dir = os.path.dirname(os.path.abspath(__file__)) +data_folder = os.environ.get("DATA_FOLDER", os.path.join(script_dir, "data_folder")) +scenarios_file = os.path.join(data_folder, "sample_data_simulation_scenarios.jsonl") + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as client, +): + # Create (or update) an agent to simulate against + agent = project_client.agents.create_version( + agent_name=agent_name, + definition=PromptAgentDefinition( + model=model_deployment_name, + instructions="You are a helpful customer service agent. Be empathetic and solution-oriented.", + ), + ) + print(f"Agent created (name: {agent.name}, version: {agent.version})") + + # Simulation uses the same "custom" eval group type as dataset evaluation (S1), + # since the generated conversations follow the same messages schema. + data_source_config = DataSourceConfigCustom( + type="custom", + item_schema={ + "type": "object", + "properties": { + "messages": {"type": "array"}, + }, + "required": ["messages"], + }, + include_sample_schema=False, + ) + + # Conversation-level evaluators + testing_criteria = [ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="customer_satisfaction", + evaluator_name="builtin.customer_satisfaction", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="task_completion", + evaluator_name="builtin.task_completion", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="conversation_coherence", + evaluator_name="builtin.coherence", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="groundedness", + evaluator_name="builtin.groundedness", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + ] + + print("Creating simulation evaluation group") + eval_object = client.evals.create( + name="Multi-turn Conversation Simulation", + data_source_config=data_source_config, + testing_criteria=testing_criteria, + ) + print(f"Evaluation created (id: {eval_object.id})") + + # Upload the simulation scenarios dataset + try: + dataset = project_client.datasets.upload_file( + name="simulation-scenarios", + version="1", + file_path=scenarios_file, + ) + assert dataset.id is not None, "Dataset upload returned no ID" + scenarios_id: str = dataset.id + print(f"Scenarios dataset uploaded (id: {scenarios_id})") + except Exception: + # Dataset already exists — use the existing URI + scenarios_id = f"azureai://accounts/{endpoint.split('/')[2].split('.')[0]}/projects/{endpoint.rstrip('/').split('/')[-1]}/data/simulation-scenarios/versions/1" + print(f"Using existing scenarios dataset (id: {scenarios_id})") + + # Create a simulation run + # - source: the seed scenarios dataset (each row is a test case) + # - target: the agent to simulate against + # - item_generation_params: controls conversation generation + # - num_conversations: conversations to generate per seed scenario + # - max_turns: maximum exchanges per conversation + # - data_mapping: maps JSONL field names to simulation parameters + eval_run = client.evals.runs.create( + eval_id=eval_object.id, + name="conversation-simulation-run", + data_source={ + "type": "azure_ai_target_completions", + "source": { + "type": "file_id", + "id": scenarios_id, + }, + "target": { + "type": "azure_ai_agent", + "name": agent.name, + "version": agent.version, + }, + "item_generation_params": { + "type": "conversation_gen_preview", + "model": model_deployment_name, + "num_conversations": 2, + "max_turns": 5, + "sampling_params": { + "temperature": 0.7, + "top_p": 1.0, + "max_completion_tokens": 800, + }, + "data_mapping": { + "test_case_description": "test_case_description", + "id": "id", + "desired_num_turns": "desired_num_turns", + }, + }, + }, # type: ignore + extra_body={"evaluation_level": "conversation"}, + ) + print(f"Simulation run created (id: {eval_run.id})") + print("Simulation runs are slow (3-8 min). Polling...") + + while True: + run = client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + if run.status in ("completed", "failed"): + break + print(f"Waiting for simulation to complete... current status: {run.status}") + time.sleep(10) + + if run.status == "completed": + print("\n✓ Simulation run completed successfully!") + print(f"Result Counts: {run.result_counts}") + # With 3 seed scenarios and num_conversations=2, expect 6 total conversations + print(f"Expected: {3 * 2} conversations (3 scenarios × 2 per scenario)") + + output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) + print(f"\nOUTPUT ITEMS (Total: {len(output_items)})") + print(f"{'-'*60}") + pprint(output_items) + print(f"{'-'*60}") + + print(f"\nEval Run Report URL: {run.report_url}") + else: + print(f"\n✗ Simulation run failed: {run.error}") + + client.evals.delete(eval_id=eval_object.id) + print("Evaluation deleted") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_trace_evaluation_agent_filter.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_trace_evaluation_agent_filter.py new file mode 100644 index 000000000000..7a65c9f6b4ba --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_trace_evaluation_agent_filter.py @@ -0,0 +1,183 @@ +# 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 evaluate multi-turn + agent conversations by filtering traces from Application Insights using an + agent name/version or agent ID, with optional smart filtering. + + This is Scenario 3 of multi-turn evaluations: instead of providing specific + conversation or trace IDs, you specify an agent identity and a time window. + The service samples traces from App Insights matching that agent and evaluates + the reconstructed conversations. + + Three agent filter forms are supported: + - agent_name + agent_version: Specify the agent by name and version separately. + - agent_id: Specify the agent as a single "name:version" string. + - smart_filtering: Use filter_strategy="smart_filtering" to bias trace + selection toward more interesting conversations. + +USAGE: + python sample_multiturn_trace_evaluation_agent_filter.py + python sample_multiturn_trace_evaluation_agent_filter.py --agent-id "my-agent:1" + python sample_multiturn_trace_evaluation_agent_filter.py --smart-filter + + Before running the sample: + + pip install "azure-ai-projects>=2.0.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint. + 2) FOUNDRY_MODEL_NAME - Required. The model deployment name for AI-assisted evaluators. + 3) FOUNDRY_AGENT_NAME - Required. The name of the agent whose traces to evaluate. + 4) FOUNDRY_AGENT_VERSION - Optional. The agent version. If not set, latest is used. +""" + +import argparse +import os +import time +from pprint import pprint +from dotenv import load_dotenv +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import TestingCriterionAzureAIEvaluator + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_deployment_name = os.environ["FOUNDRY_MODEL_NAME"] +agent_name = os.environ["FOUNDRY_AGENT_NAME"] +agent_version = os.environ.get("FOUNDRY_AGENT_VERSION", "") + + +def main() -> None: + parser = argparse.ArgumentParser(description="Evaluate agent traces using agent filter.") + parser.add_argument("--agent-id", default=None, help='Agent ID in "name:version" format') + parser.add_argument("--smart-filter", action="store_true", help="Use smart_filtering strategy") + parser.add_argument("--max-traces", type=int, default=5, help="Max traces to evaluate (default: 5)") + parser.add_argument("--lookback-hours", type=int, default=24, help="Hours to look back (default: 24)") + args = parser.parse_args() + + with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as client, + ): + # Eval group for trace-based evaluations + data_source_config = { + "type": "azure_ai_source", + "scenario": "traces", + } + + testing_criteria = [ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="customer_satisfaction", + evaluator_name="builtin.customer_satisfaction", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="task_completion", + evaluator_name="builtin.task_completion", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="conversation_coherence", + evaluator_name="builtin.coherence", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="groundedness", + evaluator_name="builtin.groundedness", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + ] + + print("Creating trace-based evaluation group") + eval_object = client.evals.create( + name="Multi-turn Trace Evaluation (Agent Filter)", + data_source_config=data_source_config, # type: ignore + testing_criteria=testing_criteria, + ) + print(f"Evaluation created (id: {eval_object.id})") + + # Compute time window in unix seconds + # Pad end_time by +600s (10 min) to avoid ingestion-delay edge exclusion + now_unix = int(time.time()) + end_time = now_unix + 600 + start_time = now_unix - (args.lookback_hours * 3600) + + # Build trace_source based on mode + trace_source: dict = { + "type": "agent_filter", + "start_time": start_time, + "end_time": end_time, + "max_traces": args.max_traces, + } + + if args.agent_id: + # agent_id form: single "name:version" string + trace_source["agent_id"] = args.agent_id + print(f"Using agent_id filter: {args.agent_id}") + else: + # agent_name + agent_version form + trace_source["agent_name"] = agent_name + if agent_version: + trace_source["agent_version"] = agent_version + print(f"Using agent filter: {agent_name} v{agent_version or '(latest)'}") + + if args.smart_filter: + trace_source["filter_strategy"] = "smart_filtering" + print("Filter strategy: smart_filtering") + + data_source = { + "type": "azure_ai_trace_data_source_preview", + "trace_source": trace_source, + } + + eval_run = client.evals.runs.create( + eval_id=eval_object.id, + name="multiturn-agent-filter-run", + data_source=data_source, # type: ignore + extra_body={"evaluation_level": "conversation"}, + ) + print(f"Evaluation run created (id: {eval_run.id})") + + while True: + run = client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + if run.status in ("completed", "failed"): + break + print(f"Waiting for eval run to complete... current status: {run.status}") + time.sleep(5) + + if run.status == "completed": + print("\n✓ Evaluation run completed successfully!") + print(f"Result Counts: {run.result_counts}") + + output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) + print(f"\nOUTPUT ITEMS (Total: {len(output_items)})") + print(f"{'-'*60}") + pprint(output_items) + print(f"{'-'*60}") + + print(f"\nEval Run Report URL: {run.report_url}") + else: + print(f"\n✗ Evaluation run failed: {run.error}") + + client.evals.delete(eval_id=eval_object.id) + print("Evaluation deleted") + + +if __name__ == "__main__": + main() diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_trace_evaluation_by_id.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_trace_evaluation_by_id.py new file mode 100644 index 000000000000..f8117be7ae3b --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_multiturn_trace_evaluation_by_id.py @@ -0,0 +1,166 @@ +# 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 evaluate multi-turn + conversations captured as agent traces in Application Insights, using specific + conversation IDs or trace IDs to select which conversations to evaluate. + + This is Scenario 2 of multi-turn evaluations: you provide known conversation + or trace identifiers, and the service reconstructs the messages from App Insights + traces, then runs conversation-level evaluators against them. + + Two modes are supported: + - conversation_id_source: Provide Foundry conversation IDs. + - trace_id_source: Provide W3C trace IDs (operation_Id from App Insights). + +USAGE: + python sample_multiturn_trace_evaluation_by_id.py + + Before running the sample: + + pip install "azure-ai-projects>=2.0.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint. + 2) FOUNDRY_MODEL_NAME - Required. The model deployment name for AI-assisted evaluators. + 3) FOUNDRY_CONVERSATION_IDS - Required (for conversation_id mode). Comma-separated + Foundry conversation IDs to evaluate. + Example: "conv_abc123,conv_def456,conv_ghi789" + 4) FOUNDRY_TRACE_IDS - Optional (for trace_id mode). Comma-separated W3C trace IDs. + If set, overrides conversation IDs. +""" + +import os +import time +from pprint import pprint +from dotenv import load_dotenv +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import TestingCriterionAzureAIEvaluator + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_deployment_name = os.environ["FOUNDRY_MODEL_NAME"] + +# Choose one: conversation IDs or trace IDs +conversation_ids_str = os.environ.get("FOUNDRY_CONVERSATION_IDS", "") +trace_ids_str = os.environ.get("FOUNDRY_TRACE_IDS", "") + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as client, +): + # Eval group for trace-based evaluations uses azure_ai_source with scenario "traces" + data_source_config = { + "type": "azure_ai_source", + "scenario": "traces", + } + + # Conversation-level evaluators for trace data + testing_criteria = [ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="customer_satisfaction", + evaluator_name="builtin.customer_satisfaction", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="task_completion", + evaluator_name="builtin.task_completion", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="conversation_coherence", + evaluator_name="builtin.coherence", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name="groundedness", + evaluator_name="builtin.groundedness", + initialization_parameters={"model": model_deployment_name}, + data_mapping={"messages": "{{item.messages}}"}, + ), + ] + + print("Creating trace-based evaluation group") + eval_object = client.evals.create( + name="Multi-turn Trace Evaluation (by ID)", + data_source_config=data_source_config, # type: ignore + testing_criteria=testing_criteria, + ) + print(f"Evaluation created (id: {eval_object.id})") + + # Build the data source based on which IDs are provided + if trace_ids_str: + # Trace ID mode — provide W3C trace IDs (operation_Id from App Insights) + trace_ids = [tid.strip() for tid in trace_ids_str.split(",") if tid.strip()] + print(f"Using {len(trace_ids)} trace IDs") + data_source = { + "type": "azure_ai_trace_data_source_preview", + "trace_source": { + "type": "trace_id_source", + "trace_ids": trace_ids, + }, + } + else: + # Conversation ID mode — provide Foundry conversation IDs + conversation_ids = [cid.strip() for cid in conversation_ids_str.split(",") if cid.strip()] + if not conversation_ids: + raise ValueError( + "Set FOUNDRY_CONVERSATION_IDS or FOUNDRY_TRACE_IDS. " + "These are IDs from prior agent interactions captured in App Insights." + ) + print(f"Using {len(conversation_ids)} conversation IDs") + data_source = { + "type": "azure_ai_trace_data_source_preview", + "trace_source": { + "type": "conversation_id_source", + "conversation_ids": conversation_ids, + }, + } + + # Create run with evaluation_level = "conversation" + eval_run = client.evals.runs.create( + eval_id=eval_object.id, + name="multiturn-trace-by-id-run", + data_source=data_source, # type: ignore + extra_body={"evaluation_level": "conversation"}, + ) + print(f"Evaluation run created (id: {eval_run.id})") + + while True: + run = client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + if run.status in ("completed", "failed"): + break + print(f"Waiting for eval run to complete... current status: {run.status}") + time.sleep(5) + + if run.status == "completed": + print("\n✓ Evaluation run completed successfully!") + print(f"Result Counts: {run.result_counts}") + + output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id)) + print(f"\nOUTPUT ITEMS (Total: {len(output_items)})") + print(f"{'-'*60}") + pprint(output_items) + print(f"{'-'*60}") + + print(f"\nEval Run Report URL: {run.report_url}") + else: + print(f"\n✗ Evaluation run failed: {run.error}") + + client.evals.delete(eval_id=eval_object.id) + print("Evaluation deleted") diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_redteam_evaluations.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_redteam_evaluations.py index 82cd63dfe664..a88d71125b12 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_redteam_evaluations.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_redteam_evaluations.py @@ -95,7 +95,7 @@ def main() -> None: # pylint: disable=too-many-statements description="Taxonomy for red teaming evaluation", taxonomy_input=agent_taxonomy_input ) - taxonomy = project_client.beta.evaluation_taxonomies.create(name=agent_name, body=eval_taxonomy_input) + taxonomy = project_client.beta.evaluation_taxonomies.create(name=agent_name, taxonomy=eval_taxonomy_input) taxonomy_path = os.path.join(tempfile.gettempdir(), f"taxonomy_{agent_name}.json") with open(taxonomy_path, "w", encoding="utf-8") as f: f.write(json.dumps(_to_json_primitive(taxonomy), indent=2)) diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_all_sources.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_all_sources.py new file mode 100644 index 000000000000..4170bbf35078 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_all_sources.py @@ -0,0 +1,222 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + End-to-end scenario showing every rubric evaluator generation source type + in a single sample file. There are four source types: + + 1. `Prompt` - an inline natural-language description of the application. + 2. `Agent` - references an agent registered in the Foundry project. + 3. `Dataset` - references an uploaded dataset (name + version). + 4. `traces` - Application Insights conversation traces for an agent, + within a time window. + + The first three source types can be combined into a single generation job + to produce a richer rubric. The `traces` source type requires a companion + source (the service rejects `traces`-only source arrays), so this sample + submits it as a separate, second job paired with an `Agent` companion. + + Optional environment variables let you skip variants where you don't have + a suitable agent, dataset, or recent traces in the target Foundry project. + +USAGE: + python sample_rubric_evaluator_generation_all_sources.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of the model the generation job + will use (e.g. `gpt-4o`, `gpt-4.1`). + 3) FOUNDRY_AGENT_NAME - Optional. Name of an agent registered in the project. + Enables the `Agent` source and the `traces`-source job. + 4) FOUNDRY_REFERENCE_DATASET_NAME - Optional. Name of an uploaded dataset. + Enables the `Dataset` source. + 5) FOUNDRY_REFERENCE_DATASET_VERSION - Optional. Version of the uploaded dataset. + Enables the `Dataset` source. + 6) FOUNDRY_TRACES_WINDOW_DAYS - Optional. Look-back window in days for the + `traces` source. Defaults to 7. + 7) POLL_INTERVAL_SECONDS - Optional. Seconds to sleep between status polls. + Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timezone +from typing import Any, Dict, List, cast + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import JobStatus, RubricBasedEvaluatorDefinition + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +agent_name = os.environ.get("FOUNDRY_AGENT_NAME") +dataset_name = os.environ.get("FOUNDRY_REFERENCE_DATASET_NAME") +dataset_version = os.environ.get("FOUNDRY_REFERENCE_DATASET_VERSION") +traces_window_days = int(os.environ.get("FOUNDRY_TRACES_WINDOW_DAYS", "7")) +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run suffix so repeated runs do not collide on evaluator name. +ts = datetime.now(tz=timezone.utc).strftime("%Y%m%d%H%M%S") +short = uuid.uuid4().hex[:6] +multi_name = f"multi-source-{ts}-{short}" +traces_name = f"traces-source-{ts}-{short}" + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +multi_evaluator_version = "" +traces_evaluator_version = "" + +with ( + DefaultAzureCredential() as credential, + # `allow_preview` and `api_version` are required for the evaluator + # generation endpoints in this preview. + AIProjectClient( + endpoint=endpoint, + credential=credential, + allow_preview=True, + api_version="2025-11-15-preview", + ) as project_client, +): + # 1. Combined Prompt + Agent + Dataset generation job. + multi_sources: List[Dict[str, Any]] = [ + { + "type": "Prompt", + "description": "Inline application overview.", + "prompt": ( + "You are evaluating a customer-support assistant that helps users " + "manage their accounts, troubleshoot issues, and place orders. The " + "assistant uses tools for account lookup, password reset, and order " + "creation. It must confirm intent before performing destructive " + "actions and maintain a patient, professional tone." + ), + } + ] + if agent_name: + multi_sources.append( + { + "type": "Agent", + "description": "Agent metadata enriches the rubric with tool and instruction signals.", + "agent_name": agent_name, + } + ) + else: + print("Skipping Agent source (FOUNDRY_AGENT_NAME not set).") + + if dataset_name and dataset_version: + multi_sources.append( + { + "type": "Dataset", + "description": "Reference examples ground dimensions in real data.", + "name": dataset_name, + "version": dataset_version, + } + ) + else: + print("Skipping Dataset source (FOUNDRY_REFERENCE_DATASET_NAME / _VERSION not set).") + + multi_job = project_client.beta.evaluators.create_generation_job( + job={ + "model": model_name, + "name": "Multi-source generation", + "evaluator_name": multi_name, + "evaluator_display_name": "Customer Support Quality (multi-source)", + "evaluator_description": "Generated from prompt, agent, and dataset signals.", + "sources": multi_sources, + }, + operation_id=f"rubric-multi-{short}", + ) + + print(f"Waiting for multi-source job `{multi_job.id}` to complete...") + while multi_job.status not in TERMINAL_STATUSES: + time.sleep(poll_interval_seconds) + multi_job = project_client.beta.evaluators.get_generation_job(multi_job.id) + + if multi_job.status != JobStatus.SUCCEEDED: + message = multi_job.error.message if multi_job.error is not None else "" + print(f"Multi-source job ended with status `{cast(JobStatus, multi_job.status).value}`: {message}") + else: + # `isinstance` narrows the discriminated `definition` to the rubric subtype. + evaluator = multi_job.result + assert evaluator is not None + definition = evaluator.definition + assert isinstance(definition, RubricBasedEvaluatorDefinition) + multi_evaluator_version = evaluator.version or "" + print( + f"Multi-source evaluator `{evaluator.name}` v{evaluator.version}: " + f"{len(definition.dimensions)} dimensions." + ) + + # 2. Separate `traces` + Agent companion generation job. + # The traces source requires a companion source because the service rejects + # sources arrays consisting only of traces. The Agent source is the typical companion. + if not agent_name: + print("Skipping traces job (requires FOUNDRY_AGENT_NAME for both the traces source and companion).") + else: + now = int(time.time()) + start_time = now - traces_window_days * 24 * 3600 + end_time = now + 600 # small padding for clock skew + + traces_job = project_client.beta.evaluators.create_generation_job( + job={ + "model": model_name, + "name": "Traces-source generation", + "evaluator_name": traces_name, + "evaluator_display_name": "Customer Support Quality (from traces)", + "evaluator_description": "Generated from real Application Insights conversation traces.", + "sources": [ + { + "type": "traces", + "description": "Application Insights conversation traces for the agent.", + "agent_name": agent_name, + "start_time": start_time, + "end_time": end_time, + }, + { + "type": "Agent", + "description": "Companion source (service rejects traces-only).", + "agent_name": agent_name, + }, + ], + }, + operation_id=f"rubric-traces-{short}", + ) + + print(f"Waiting for traces job `{traces_job.id}` to complete...") + while traces_job.status not in TERMINAL_STATUSES: + time.sleep(poll_interval_seconds) + traces_job = project_client.beta.evaluators.get_generation_job(traces_job.id) + + if traces_job.status != JobStatus.SUCCEEDED: + message = traces_job.error.message if traces_job.error is not None else "" + print(f"Traces job ended with status `{cast(JobStatus, traces_job.status).value}`: {message}") + else: + evaluator = traces_job.result + assert evaluator is not None + definition = evaluator.definition + assert isinstance(definition, RubricBasedEvaluatorDefinition) + traces_evaluator_version = evaluator.version or "" + print( + f"Traces evaluator `{evaluator.name}` v{evaluator.version}: " + f"{len(definition.dimensions)} dimensions." + ) + + # 3. Clean up. `delete_version` cascades to delete the generation job record. + print("Cleaning up.") + if multi_evaluator_version: + project_client.beta.evaluators.delete_version(name=multi_name, version=multi_evaluator_version) + if traces_evaluator_version: + project_client.beta.evaluators.delete_version(name=traces_name, version=traces_evaluator_version) diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_basic.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_basic.py new file mode 100644 index 000000000000..d9514e0b6095 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_basic.py @@ -0,0 +1,213 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + End-to-end scenario showing rubric evaluator generation from a single + `Prompt` source, followed by an OpenAI evaluation run that uses the + generated evaluator. The sample: + + 1. Creates an `EvaluatorGenerationJob` whose only source is an inline + natural-language description of the application's purpose, capabilities, + and tools. The service synthesizes a rubric tailored to that application. + 2. Polls the generation job to completion and resolves the generated + `EvaluatorVersion`. + 3. Creates an OpenAI evaluation referencing the generated evaluator as a + testing criterion. + 4. Runs the evaluation against inline JSONL sample data. + 5. Cleans up the evaluation and the evaluator version. Deleting the + evaluator version cascades to delete the generation job record. + + Other source types - `Agent`, `Dataset`, and `traces` - can be used in + place of (or alongside) the prompt source. See + `sample_rubric_evaluator_generation_all_sources.py` for examples of each. + +USAGE: + python sample_rubric_evaluator_generation_basic.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of the model used by both the + generation job and the eval run's LLM judge (e.g. `gpt-4o`, `gpt-4.1`). + The generation runs inline server side (no deployment required), but the + eval run's grader does require a model deployment in your project. + 3) POLL_INTERVAL_SECONDS - Optional. Seconds to sleep between status polls + for both the generation job and the evaluation run. Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timezone +from typing import cast + +from dotenv import load_dotenv +from openai.types.eval_create_params import DataSourceConfigCustom +from openai.types.evals.create_eval_jsonl_run_data_source_param import ( + CreateEvalJSONLRunDataSourceParam, + SourceFileContent, + SourceFileContentContent, +) + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + JobStatus, + RubricBasedEvaluatorDefinition, + TestingCriterionAzureAIEvaluator, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run name so repeated runs do not collide. +ts = datetime.now(tz=timezone.utc).strftime("%Y%m%d%H%M%S") +short = uuid.uuid4().hex[:6] +evaluator_name = f"reservation-quality-generated-{ts}-{short}" + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} +TERMINAL_RUN_STATUSES = {"completed", "failed", "canceled"} + +with ( + DefaultAzureCredential() as credential, + # `allow_preview` and `api_version` are required for the evaluator + # generation endpoints in this preview. + AIProjectClient( + endpoint=endpoint, + credential=credential, + allow_preview=True, + api_version="2025-11-15-preview", + ) as project_client, + project_client.get_openai_client() as openai_client, +): + # 1. Generate an evaluator from a single `Prompt` source. + job = project_client.beta.evaluators.create_generation_job( + job={ + "model": model_name, + "name": "Reservation Quality (Generated)", + "evaluator_name": evaluator_name, + "evaluator_display_name": "Reservation Quality (Generated)", + "evaluator_description": "Quality evaluator generated from a prompt describing a restaurant reservation assistant.", + "sources": [ + { + "type": "Prompt", + "description": "Application overview - purpose, capabilities, and tools.", + "prompt": ( + "You are evaluating a restaurant reservation assistant. The assistant helps " + "users create, modify, and cancel reservations at participating restaurants. " + "It can:\n" + " - Search for restaurants by name, cuisine, or neighborhood.\n" + " - Check table availability for a requested date, time, and party size.\n" + " - Create, update, and cancel reservations on behalf of the user.\n" + " - Send SMS or email confirmations through a notifications tool.\n" + "It must always confirm the user's intent before committing changes, " + "ask follow-up questions when details are missing, and maintain a polite " + "restaurant-host tone." + ), + } + ], + }, + # `operation_id` makes the call idempotent - re-submitting the same id returns the existing job. + operation_id=f"rubric-eval-basic-{short}", + ) + print(f"Created generation job `{job.id}`.") + + print(f"Waiting for job `{job.id}` to complete...") + while job.status not in TERMINAL_STATUSES: + time.sleep(poll_interval_seconds) + job = project_client.beta.evaluators.get_generation_job(job.id) + print(f"Job finished with status `{cast(JobStatus, job.status).value}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Generation job ended with status `{cast(JobStatus, job.status).value}`: {message}") + + # On success, the evaluator is automatically saved as version 1. + # `isinstance` narrows the discriminated `definition` to the rubric subtype. + evaluator = job.result + assert evaluator is not None + definition = evaluator.definition + assert isinstance(definition, RubricBasedEvaluatorDefinition) + print( + f"Generated evaluator `{evaluator.name}` v{evaluator.version}: " + f"{len(definition.dimensions)} dimensions, pass_threshold={definition.pass_threshold}." + ) + print(f" Dimensions: {', '.join(d.id for d in definition.dimensions)}") + + # 2. Create an OpenAI evaluation that uses the generated evaluator. + eval_object = openai_client.evals.create( + name=f"{evaluator.name}-eval", + data_source_config=DataSourceConfigCustom( + type="custom", + item_schema={ + "type": "object", + "properties": { + "query": {"type": "string"}, + "response": {"type": "string"}, + }, + "required": ["query", "response"], + }, + include_sample_schema=True, + ), + testing_criteria=[ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name=evaluator.name, + evaluator_name=evaluator.name, + initialization_parameters={"deployment_name": model_name}, + data_mapping={ + "query": "{{item.query}}", + "response": "{{item.response}}", + }, + ) + ], + ) + + # 3. Run the evaluation against inline JSONL sample data. + eval_run = openai_client.evals.runs.create( + eval_id=eval_object.id, + name=f"{evaluator.name}-run", + metadata={"sample": "rubric_evaluator_generation_basic"}, + data_source=CreateEvalJSONLRunDataSourceParam( + type="jsonl", + source=SourceFileContent( + type="file_content", + content=[ + SourceFileContentContent( + item={ + "query": "Book a table for 4 tomorrow at 7 PM.", + "response": "Booked - table for 4 tomorrow at 7:00 PM. A confirmation SMS is on its way.", + } + ), + SourceFileContentContent( + item={ + "query": "Cancel my reservation for Friday night.", + "response": "Sure.", + } + ), + ], + ), + ), + ) + + print(f"Waiting for eval run `{eval_run.id}` to complete...") + while eval_run.status not in TERMINAL_RUN_STATUSES: + time.sleep(poll_interval_seconds) + eval_run = openai_client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + print(f"Eval run finished with status `{eval_run.status}`. Result counts: {eval_run.result_counts}.") + + # 4. Clean up. `delete_version` cascades to delete the generation job record. + print("Cleaning up.") + openai_client.evals.delete(eval_id=eval_object.id) + project_client.beta.evaluators.delete_version(name=evaluator.name, version=evaluator.version) diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_iterate.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_iterate.py new file mode 100644 index 000000000000..e8f7df81a664 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_iterate.py @@ -0,0 +1,198 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + End-to-end scenario showing the human-in-the-loop iteration workflow for + rubric evaluators. This is the typical pattern when the first generated + rubric is a good starting point but a domain expert wants to tune the + weighting or add custom dimensions. The sample: + + 1. Generates v1 of an evaluator from a single `Prompt` source. + 2. Edits the dimensions locally - boosts the highest-weight editable + dimension to 10, drops the lowest-weight editable dimension, and + adds a new custom dimension. The non-editable `general_quality` + ALWAYS-ON dimension is preserved verbatim. + 3. Saves the edited definition as v2 with `create_version`. + 4. Calls `list_versions` to enumerate v1 and v2. + 5. Cleans up by deleting both versions. + +USAGE: + python sample_rubric_evaluator_generation_iterate.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of the model the generation job + will use (e.g. `gpt-4o`, `gpt-4.1`). + 3) POLL_INTERVAL_SECONDS - Optional. Seconds to sleep between status polls. + Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timezone +from typing import cast + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + EvaluatorCategory, + EvaluatorDefinitionType, + JobStatus, + RubricBasedEvaluatorDefinition, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run name so repeated runs do not collide. +ts = datetime.now(tz=timezone.utc).strftime("%Y%m%d%H%M%S") +short = uuid.uuid4().hex[:6] +evaluator_name = f"reservation-quality-iterate-{ts}-{short}" + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +with ( + DefaultAzureCredential() as credential, + # `allow_preview` and `api_version` are required for the evaluator + # generation endpoints in this preview. + AIProjectClient( + endpoint=endpoint, + credential=credential, + allow_preview=True, + api_version="2025-11-15-preview", + ) as project_client, +): + # 1. Generate v1 of the evaluator from a single `Prompt` source. + job = project_client.beta.evaluators.create_generation_job( + job={ + "model": model_name, + "name": "Reservation Quality (iterate)", + "evaluator_name": evaluator_name, + "evaluator_display_name": "Reservation Quality (iterate)", + "evaluator_description": "Starting point for human-in-the-loop iteration.", + "sources": [ + { + "type": "Prompt", + "description": "Inline application overview.", + "prompt": ( + "You are evaluating a restaurant reservation assistant that creates, " + "modifies, and cancels reservations. It uses tools for restaurant " + "lookup, availability checking, and notifications. It must confirm " + "user intent before committing changes." + ), + } + ], + }, + operation_id=f"rubric-iterate-{short}", + ) + + print(f"Waiting for job `{job.id}` to complete...") + while job.status not in TERMINAL_STATUSES: + time.sleep(poll_interval_seconds) + job = project_client.beta.evaluators.get_generation_job(job.id) + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Generation job ended with status `{cast(JobStatus, job.status).value}`: {message}") + + # `isinstance` narrows the discriminated `definition` to the rubric subtype. + v1 = job.result + assert v1 is not None + v1_definition = v1.definition + assert isinstance(v1_definition, RubricBasedEvaluatorDefinition) + print(f"v1 created with {len(v1_definition.dimensions)} dimensions: {', '.join(d.id for d in v1_definition.dimensions)}") + + # 2. Edit dimensions locally. + # Domain-expert edits: + # * Always preserve the ALWAYS-ON `general_quality` residual dimension + # exactly as-is (id, weight, description, always_applicable). + # * Boost the most important editable dimension to weight 10. + # * Drop the lowest-weight editable dimension as redundant. + # * Add a new custom dimension specific to this assistant. + editable = [d for d in v1_definition.dimensions if not d.always_applicable] + always_on = [d for d in v1_definition.dimensions if d.always_applicable] + + edited_dimensions = [] + if editable: + top = max(editable, key=lambda d: d.weight) + lowest = min(editable, key=lambda d: d.weight) + for dim in editable: + if dim.id == lowest.id: + continue + edited_dimensions.append( + { + "id": dim.id, + "description": dim.description, + "weight": 10 if dim.id == top.id else dim.weight, + } + ) + + edited_dimensions.append( + { + "id": "wait_time_expectations_set", + "description": ( + "Sets clear expectations about wait time, table readiness, or confirmation " + "delivery so the user knows what happens next." + ), + "weight": 4, + } + ) + + # Preserve every ALWAYS-ON dimension verbatim. These are non-editable. + for dim in always_on: + edited_dimensions.append( + { + "id": dim.id, + "description": dim.description, + "weight": dim.weight, + "always_applicable": True, + } + ) + + # 3. Save the edited definition as v2. + v2 = project_client.beta.evaluators.create_version( + name=evaluator_name, + evaluator_version={ + "name": evaluator_name, + # Narrow each category to its enum value (the categories list is Union[str, EvaluatorCategory]). + "categories": [c.value if isinstance(c, EvaluatorCategory) else c for c in v1.categories], + "display_name": v1.display_name, + "description": (v1.description or "") + " (edited)", + "definition": { + "type": EvaluatorDefinitionType.RUBRIC, + "dimensions": edited_dimensions, + "pass_threshold": v1_definition.pass_threshold or 0.6, + }, + }, + ) + v2_definition = v2.definition + assert isinstance(v2_definition, RubricBasedEvaluatorDefinition) + print(f"v2 created with {len(v2_definition.dimensions)} dimensions: {', '.join(d.id for d in v2_definition.dimensions)}") + + # 4. List all versions of the evaluator. + print(f"All versions of `{evaluator_name}`:") + for ver in project_client.beta.evaluators.list_versions(name=evaluator_name): + ver_definition = ver.definition + assert isinstance(ver_definition, RubricBasedEvaluatorDefinition) + print(f" - v{ver.version}: {len(ver_definition.dimensions)} dimensions") + + # 5. Clean up. Delete the highest version first to avoid any ordering issues. + print("Cleaning up.") + for version in (v2.version, v1.version): + if version: + project_client.beta.evaluators.delete_version(name=evaluator_name, version=version) diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_lifecycle.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_lifecycle.py new file mode 100644 index 000000000000..8f949ffe3c41 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_generation_lifecycle.py @@ -0,0 +1,134 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + End-to-end scenario showing the lifecycle of rubric evaluator generation + jobs. The sample exercises: + + * `create_generation_job` with `operation_id` for idempotent re-submits. + * `get_generation_job` to poll a single job to completion. + * `list_generation_jobs` to enumerate recent jobs in the project. + * `delete_generation_job` to remove a finished job record. + * `delete_version` to remove the persisted evaluator that the job produced. + + `cancel_generation_job` is not exercised here - cancelling requires catching + a job mid-flight and jobs usually finish in under two minutes. + + Note: `delete_version` cascades to delete the generation job record as well, + so `delete_generation_job` may return 404 - that is expected and tolerated + below. + +USAGE: + python sample_rubric_evaluator_generation_lifecycle.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of the model the generation job + will use (e.g. `gpt-4o`, `gpt-4.1`). + 3) POLL_INTERVAL_SECONDS - Optional. Seconds to sleep between status polls. + Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timezone +from typing import cast + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import JobStatus, PageOrder + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run name so repeated runs do not collide. +ts = datetime.now(tz=timezone.utc).strftime("%Y%m%d%H%M%S") +short = uuid.uuid4().hex[:6] +evaluator_name = f"lifecycle-demo-{ts}-{short}" +operation_id = f"rubric-lifecycle-{short}" + +TERMINAL_STATUSES = {JobStatus.SUCCEEDED, JobStatus.FAILED, JobStatus.CANCELLED} + +# Shared job body used both for the initial create and the idempotency replay. +job_body = { + "model": model_name, + "name": "Lifecycle demo", + "evaluator_name": evaluator_name, + "evaluator_display_name": "Lifecycle demo", + "evaluator_description": "Minimal job used to demonstrate the LRO + list/delete lifecycle.", + "sources": [ + { + "type": "Prompt", + "description": "Inline application overview.", + "prompt": "You are evaluating a simple Q&A assistant that answers factual questions clearly and concisely.", + } + ], +} + +with ( + DefaultAzureCredential() as credential, + # `allow_preview` and `api_version` are required for the evaluator + # generation endpoints in this preview. + AIProjectClient( + endpoint=endpoint, + credential=credential, + allow_preview=True, + api_version="2025-11-15-preview", + ) as project_client, +): + # 1. Create the generation job. `operation_id` makes the call idempotent - + # re-submitting with the same id returns the existing job. + job = project_client.beta.evaluators.create_generation_job(job=job_body, operation_id=operation_id) + print(f"Created generation job `{job.id}`.") + + replay = project_client.beta.evaluators.create_generation_job(job=job_body, operation_id=operation_id) + assert replay.id == job.id # idempotent replay returns the same job + + # 2. Poll the job to completion. + print(f"Waiting for job `{job.id}` to complete...") + while job.status not in TERMINAL_STATUSES: + time.sleep(poll_interval_seconds) + job = project_client.beta.evaluators.get_generation_job(job.id) + print(f"Job finished with status `{cast(JobStatus, job.status).value}`.") + + if job.status != JobStatus.SUCCEEDED: + message = job.error.message if job.error is not None else "" + raise RuntimeError(f"Generation job ended with status `{cast(JobStatus, job.status).value}`: {message}") + + evaluator = job.result + assert evaluator is not None + print(f"Generated evaluator `{evaluator.name}` version `{evaluator.version}`.") + + # 3. List the 5 most recent generation jobs in this project. + print("Recent generation jobs:") + for entry in project_client.beta.evaluators.list_generation_jobs(limit=5, order=PageOrder.DESC): + entry_name = entry.inputs.evaluator_name if entry.inputs is not None else "" + print(f" - id=`{entry.id}` status=`{cast(JobStatus, entry.status).value}` evaluator_name=`{entry_name}`") + + # 4. Cancel a running job (not exercised here; the job above already completed). + # cancelled = project_client.beta.evaluators.cancel_generation_job(some_running_job_id) + + # 5. Clean up. `delete_version` cascades to the generation job record, so + # the explicit delete below may return 404. + print("Cleaning up.") + project_client.beta.evaluators.delete_version(name=evaluator.name, version=evaluator.version) + try: + project_client.beta.evaluators.delete_generation_job(job.id) + except ResourceNotFoundError: + pass # already removed by the delete_version cascade diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_manual.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_manual.py new file mode 100644 index 000000000000..9b8c6ae6be96 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_rubric_evaluator_manual.py @@ -0,0 +1,225 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + End-to-end scenario showing how to manually author a rubric-based + evaluator and use it as a testing criterion of an OpenAI evaluation run. + The sample: + + 1. Creates a rubric evaluator with `project_client.beta.evaluators.create_version`, + supplying scoring dimensions (each with an id, description, and integer + weight from 1-10) and an optional pass threshold. + 2. Creates an OpenAI evaluation referencing the rubric as a testing criterion. + 3. Runs the evaluation against inline JSONL sample data and prints per-item + scores. + 4. Cleans up the evaluation and the evaluator version. + + A rubric evaluator is a collection of independent scoring dimensions. At + evaluation time, an LLM judge scores each applicable dimension on a 1-5 + scale and the runtime emits a normalized aggregate score. Dimensions can + opt in to `always_applicable` to skip the applicability assessment. + + See `sample_rubric_evaluator_generation_basic.py` for the generation-based + workflow that produces the same rubric structure automatically from a + description of the application. + +USAGE: + python sample_rubric_evaluator_manual.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity 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) FOUNDRY_MODEL_NAME - Required. The name of the LLM model deployment that + the rubric evaluator's judge will use at evaluation time (e.g. `gpt-4o`, `gpt-4.1`). + 3) POLL_INTERVAL_SECONDS - Optional. Seconds to sleep between status polls + for the evaluation run. Defaults to 10. +""" + +import os +import time +import uuid +from datetime import datetime, timezone + +from dotenv import load_dotenv +from openai.types.eval_create_params import DataSourceConfigCustom +from openai.types.evals.create_eval_jsonl_run_data_source_param import ( + CreateEvalJSONLRunDataSourceParam, + SourceFileContent, + SourceFileContentContent, +) + +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + EvaluatorCategory, + EvaluatorDefinitionType, + RubricBasedEvaluatorDefinition, + TestingCriterionAzureAIEvaluator, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ["FOUNDRY_MODEL_NAME"] +poll_interval_seconds = int(os.environ.get("POLL_INTERVAL_SECONDS", "10")) + +# Unique per-run name so repeated runs do not collide. +ts = datetime.now(tz=timezone.utc).strftime("%Y%m%d%H%M%S") +short = uuid.uuid4().hex[:6] +evaluator_name = f"reservation-quality-manual-{ts}-{short}" + +TERMINAL_RUN_STATUSES = {"completed", "failed", "canceled"} + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + project_client.get_openai_client() as openai_client, +): + # 1. Author the rubric evaluator. + # Each dimension is scored independently on a 1-5 scale by an LLM judge at + # evaluation time. `weight` (1-10) controls how strongly each dimension + # contributes to the normalized aggregate score. + evaluator = project_client.beta.evaluators.create_version( + name=evaluator_name, + evaluator_version={ + "name": evaluator_name, + "categories": [EvaluatorCategory.QUALITY], + "display_name": "Reservation Quality (Manual)", + "description": ( + "Hand-authored rubric evaluating a reservation assistant on intent " + "resolution, completeness, and tone." + ), + "definition": { + "type": EvaluatorDefinitionType.RUBRIC, + "dimensions": [ + { + "id": "correct_intent_resolution", + "description": ( + "Correctly identifies the user's reservation intent (new booking, " + "modification, or cancellation) and pursues the right workflow." + ), + "weight": 9, + }, + { + "id": "completeness", + "description": ( + "Captures or confirms every reservation detail the user needs " + "(party size, date, time, contact info) before completing the task." + ), + "weight": 6, + }, + { + "id": "professional_tone", + "description": "Maintains a polite, professional, restaurant-host tone throughout.", + "weight": 3, + }, + ], + # `pass_threshold` sets the normalized 0.0-1.0 pass/fail threshold (default 0.5). + "pass_threshold": 0.6, + }, + }, + ) + # `isinstance` narrows the discriminated `definition` to the rubric subtype. + definition = evaluator.definition + assert isinstance(definition, RubricBasedEvaluatorDefinition) + print(f"Created evaluator `{evaluator.name}` version `{evaluator.version}` with {len(definition.dimensions)} dimensions.") + + # 2. Create an OpenAI evaluation that uses the rubric as a testing criterion. + eval_object = openai_client.evals.create( + name=f"{evaluator_name}-eval", + data_source_config=DataSourceConfigCustom( + type="custom", + item_schema={ + "type": "object", + "properties": { + "query": {"type": "string"}, + "response": {"type": "string"}, + }, + "required": ["query", "response"], + }, + include_sample_schema=True, + ), + testing_criteria=[ + TestingCriterionAzureAIEvaluator( + type="azure_ai_evaluator", + name=evaluator_name, + evaluator_name=evaluator_name, + # The LLM judge for the rubric uses the deployment supplied here. + initialization_parameters={"deployment_name": model_name}, + data_mapping={ + "query": "{{item.query}}", + "response": "{{item.response}}", + }, + ) + ], + ) + + # 3. Run the evaluation against inline JSONL sample data. + eval_run = openai_client.evals.runs.create( + eval_id=eval_object.id, + name=f"{evaluator_name}-run", + metadata={"sample": "evaluator_rubric_manual"}, + data_source=CreateEvalJSONLRunDataSourceParam( + type="jsonl", + source=SourceFileContent( + type="file_content", + content=[ + SourceFileContentContent( + item={ + "query": "Can I book a table for 4 tomorrow at 7 PM?", + "response": ( + "Absolutely - I have you down for a table for 4 tomorrow at 7:00 PM. " + "Could you share a contact number in case anything changes?" + ), + } + ), + SourceFileContentContent( + item={ + "query": "I need to cancel my reservation for Friday.", + "response": "ok", + } + ), + SourceFileContentContent( + item={ + "query": "Can you move my Saturday 8 PM reservation to 8:30?", + "response": ( + "Of course. I've updated your Saturday reservation from 8:00 PM to 8:30 PM. " + "Anything else I can help with?" + ), + } + ), + ], + ), + ), + ) + + print(f"Waiting for eval run `{eval_run.id}` to complete...") + while eval_run.status not in TERMINAL_RUN_STATUSES: + time.sleep(poll_interval_seconds) + eval_run = openai_client.evals.runs.retrieve(run_id=eval_run.id, eval_id=eval_object.id) + print(f"Eval run finished with status `{eval_run.status}`. Result counts: {eval_run.result_counts}.") + + if eval_run.status == "completed": + for idx, item in enumerate( + openai_client.evals.runs.output_items.list(run_id=eval_run.id, eval_id=eval_object.id), start=1 + ): + # Result entries may be typed objects (Azure AI evaluators) or plain dicts (some OpenAI evaluators). + scores = [] + for r in getattr(item, "results", None) or []: + name = r.get("name", "?") if isinstance(r, dict) else getattr(r, "name", "?") + score = r.get("score", "n/a") if isinstance(r, dict) else getattr(r, "score", "n/a") + scores.append(f"{name}={score}") + print(f" item {idx} ({item.status}): {', '.join(scores)}") + + # 4. Clean up. + print("Cleaning up.") + openai_client.evals.delete(eval_id=eval_object.id) + project_client.beta.evaluators.delete_version(name=evaluator_name, version=evaluator.version) diff --git a/sdk/ai/azure-ai-projects/samples/evaluations/sample_scheduled_evaluations.py b/sdk/ai/azure-ai-projects/samples/evaluations/sample_scheduled_evaluations.py index 85c89d83abad..3d799a452c2c 100644 --- a/sdk/ai/azure-ai-projects/samples/evaluations/sample_scheduled_evaluations.py +++ b/sdk/ai/azure-ai-projects/samples/evaluations/sample_scheduled_evaluations.py @@ -258,14 +258,14 @@ def schedule_dataset_evaluation() -> None: name="violence", evaluator_name="builtin.violence", data_mapping={"query": "{{item.query}}", "response": "{{item.response}}"}, - initialization_parameters={"deployment_name": "{{aoai_deployment_and_model}}"}, + initialization_parameters={"model": "{{aoai_deployment_and_model}}"}, ), TestingCriterionAzureAIEvaluator(type="azure_ai_evaluator", name="f1", evaluator_name="builtin.f1_score"), TestingCriterionAzureAIEvaluator( type="azure_ai_evaluator", name="coherence", evaluator_name="builtin.coherence", - initialization_parameters={"deployment_name": "{{aoai_deployment_and_model}}"}, + initialization_parameters={"model": "{{aoai_deployment_and_model}}"}, ), ] @@ -380,7 +380,7 @@ def schedule_redteam_evaluation() -> None: # pylint: disable=too-many-locals description="Taxonomy for red teaming evaluation", taxonomy_input=agent_taxonomy_input ) - taxonomy = project_client.beta.evaluation_taxonomies.create(name=agent_name, body=eval_taxonomy_input) + taxonomy = project_client.beta.evaluation_taxonomies.create(name=agent_name, taxonomy=eval_taxonomy_input) taxonomy_path = os.path.join(data_folder, f"taxonomy_{agent_name}.json") # Create the data folder if it doesn't exist os.makedirs(data_folder, exist_ok=True) diff --git a/sdk/ai/azure-ai-projects/samples/files/sample_files.py b/sdk/ai/azure-ai-projects/samples/files/sample_files.py index 8c96a934f300..6e6502a10193 100644 --- a/sdk/ai/azure-ai-projects/samples/files/sample_files.py +++ b/sdk/ai/azure-ai-projects/samples/files/sample_files.py @@ -39,7 +39,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, project_client.get_openai_client() as openai_client, ): - # [START files_sample] print("Uploading file") with open(file_path, "rb") as f: uploaded_file = openai_client.files.create(file=f, purpose="fine-tune") @@ -64,4 +63,3 @@ print(f"Deleting file with ID: {processed_file.id}") deleted_file = openai_client.files.delete(processed_file.id) print(f"Successfully deleted file: {deleted_file.id}") - # [END files_sample] diff --git a/sdk/ai/azure-ai-projects/samples/finetuning/sample_finetuning_oss_models_supervised_job.py b/sdk/ai/azure-ai-projects/samples/finetuning/sample_finetuning_oss_models_supervised_job.py index d944f157314c..15f5b6e26a2c 100644 --- a/sdk/ai/azure-ai-projects/samples/finetuning/sample_finetuning_oss_models_supervised_job.py +++ b/sdk/ai/azure-ai-projects/samples/finetuning/sample_finetuning_oss_models_supervised_job.py @@ -44,7 +44,6 @@ project_client.get_openai_client() as openai_client, ): - # [START finetuning_oss_model_supervised_job_sample] print("Uploading training file...") with open(training_file_path, "rb") as f: train_file = openai_client.files.create(file=f, purpose="fine-tune") @@ -75,4 +74,3 @@ # Learn more - https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/ and https://azure.microsoft.com/explore/global-infrastructure/data-residency/ ) print(fine_tuning_job) - # [END finetuning_oss_model_supervised_job_sample] diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent-prebuilt.zip b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent-prebuilt.zip new file mode 100644 index 000000000000..99c68e9b0b6b Binary files /dev/null and b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent-prebuilt.zip differ diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent.zip b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent.zip new file mode 100644 index 000000000000..133f1995d33a Binary files /dev/null and b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent.zip differ diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/Dockerfile b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/Dockerfile similarity index 100% rename from sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/Dockerfile rename to sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/Dockerfile diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/README.md b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/README.md similarity index 100% rename from sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/README.md rename to sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/README.md diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/main.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/main.py similarity index 100% rename from sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/main.py rename to sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/main.py diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/requirements.txt b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/requirements.txt new file mode 100644 index 000000000000..baffc50b482c --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/echo-agent/requirements.txt @@ -0,0 +1,3 @@ +azure-ai-agentserver-core==2.0.0b3 +azure-ai-agentserver-invocations==1.0.0b3 +azure-ai-agentserver-responses==1.0.0b5 diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/requirements.txt b/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/requirements.txt deleted file mode 100644 index 65ee9848e259..000000000000 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/assets/responses-echo-agent/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ ---index-url https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/ -azure-ai-agentserver-core==2.0.0a20260410006 -azure-ai-agentserver-invocations==1.0.0a20260410006 -azure-ai-agentserver-responses==1.0.0a20260410006 diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/hosted_agents_util.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/hosted_agents_util.py index 9641a6fb2616..ede784f3db33 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/hosted_agents_util.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/hosted_agents_util.py @@ -1,12 +1,44 @@ import asyncio -import logging +import hashlib import time -from contextlib import asynccontextmanager, contextmanager -from typing import AsyncGenerator, Optional +from pathlib import Path +from typing import Tuple from azure.ai.projects import AIProjectClient from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient -from azure.ai.projects.models import HostedAgentDefinition, ProtocolVersionRecord, VersionRefIndicator +from azure.ai.projects.models import ( + AgentVersionDetails, + CodeDependencyResolution, +) + +_ASSETS_DIR = Path(__file__).parent / "assets" + + +def select_echo_agent_code_zip( + use_remote_build: bool, +) -> Tuple[CodeDependencyResolution, str, bytes, str]: + """Pick the dependency-resolution mode and matching echo-agent zip, and load it. + + When ``use_remote_build`` is ``True``, returns REMOTE_BUILD with + ``assets/echo-agent.zip``; otherwise BUNDLED with + ``assets/echo-agent-prebuilt.zip``. + + Reads the zip bytes, computes its SHA-256, and prints a one-line summary. + + Returns ``(dependency_resolution, zip_filename, zip_bytes, zip_sha256)``. + """ + dependency_resolution = ( + CodeDependencyResolution.REMOTE_BUILD if use_remote_build else CodeDependencyResolution.BUNDLED + ) + zip_filename = "echo-agent.zip" if use_remote_build else "echo-agent-prebuilt.zip" + zip_path = _ASSETS_DIR / zip_filename + zip_bytes = zip_path.read_bytes() + zip_sha256 = hashlib.sha256(zip_bytes).hexdigest() + print( + f"Loaded code zip from {zip_path} (dependency_resolution={dependency_resolution.value}): " + f"{len(zip_bytes)} bytes, sha256={zip_sha256}" + ) + return dependency_resolution, zip_filename, zip_bytes, zip_sha256 def wait_for_agent_version_active( @@ -14,34 +46,26 @@ def wait_for_agent_version_active( agent_name: str, agent_version: str, *, - logger: Optional[logging.Logger] = None, max_attempts: int = 60, poll_interval_seconds: int = 10, ) -> None: - if logger: - logger.info("Waiting for agent version to become active...") + """Poll until the version becomes ``active``; raise on ``failed`` or timeout.""" + print("Waiting for agent version to become active...") for attempt in range(max_attempts): time.sleep(poll_interval_seconds) version_details = project_client.agents.get_version(agent_name=agent_name, agent_version=agent_version) - status = version_details.status + status = version_details["status"] - if logger: - logger.debug(f"Agent version status: {status} (attempt {attempt + 1}/{max_attempts})") - print(f"Agent version status: {status} (attempt {attempt + 1})") + print(f"Agent version status: {status} (attempt {attempt + 1}/{max_attempts})") if status == "active": - if logger: - logger.info("Agent version is now active") + print("Agent version is now active") return if status == "failed": - if logger: - logger.error(f"Agent version provisioning failed: {dict(version_details)}") raise RuntimeError(f"Agent version provisioning failed: {dict(version_details)}") - if logger: - logger.error("Timed out waiting for agent version to become active") raise RuntimeError("Timed out waiting for agent version to become active") @@ -50,128 +74,52 @@ async def wait_for_agent_version_active_async( agent_name: str, agent_version: str, *, - logger: Optional[logging.Logger] = None, max_attempts: int = 60, poll_interval_seconds: int = 10, ) -> None: - if logger: - logger.info("Waiting for agent version to become active...") + """Async variant of :func:`wait_for_agent_version_active`.""" + print("Waiting for agent version to become active...") for attempt in range(max_attempts): await asyncio.sleep(poll_interval_seconds) version_details = await project_client.agents.get_version(agent_name=agent_name, agent_version=agent_version) status = version_details["status"] - if logger: - logger.debug(f"Agent version status: {status} (attempt {attempt + 1}/{max_attempts})") - print(f"Agent version status: {status} (attempt {attempt + 1})") + print(f"Agent version status: {status} (attempt {attempt + 1}/{max_attempts})") if status == "active": - if logger: - logger.info("Agent version is now active") + print("Agent version is now active") return if status == "failed": - if logger: - logger.error(f"Agent version provisioning failed: {dict(version_details)}") raise RuntimeError(f"Agent version provisioning failed: {dict(version_details)}") - if logger: - logger.error("Timed out waiting for agent version to become active") raise RuntimeError("Timed out waiting for agent version to become active") -@contextmanager -def create_agent_and_session( +def get_latest_active_agent_version( project_client: AIProjectClient, agent_name: str, - image: str, - isolation_key: str = "sample-isolation-key", -): - agent = project_client.agents.create_version( - agent_name=agent_name, - definition=HostedAgentDefinition( - cpu="0.5", - memory="1Gi", - image=image, - container_protocol_versions=[ - ProtocolVersionRecord(protocol="responses", version="1.0.0"), - ], - ), - metadata={"enableVnextExperience": "true"}, +) -> AgentVersionDetails: + for version in project_client.agents.list_versions(agent_name=agent_name, order="desc"): + if version.status == "active": + return version + + raise RuntimeError( + f"No active version found for hosted agent '{agent_name}'. " + "Create or activate a version before running this sample." ) - print(f"Agent created (name: {agent.name}, version: {agent.version})") - wait_for_agent_version_active( - project_client=project_client, - agent_name=agent_name, - agent_version=agent.version, - ) - session = project_client.beta.agents.create_session( - agent_name=agent_name, - isolation_key=isolation_key, - version_indicator=VersionRefIndicator(agent_version=agent.version), - ) - print(f"Session created (id: {session.agent_session_id}, status: {session.status})") - - try: - yield agent, session - finally: - project_client.beta.agents.delete_session( - agent_name=agent_name, - session_id=session.agent_session_id, - isolation_key=isolation_key, - ) - print(f"Session with id: {session.agent_session_id} deleted.") - - project_client.agents.delete_version(agent_name=agent_name, agent_version=agent.version) - print(f"Agent version {agent.version} deleted.") - - -@asynccontextmanager -async def create_agent_and_session_async( +async def get_latest_active_agent_version_async( project_client: AsyncAIProjectClient, agent_name: str, - image: str, - isolation_key: str = "sample-isolation-key", -) -> AsyncGenerator[tuple[str, str], None]: - agent = await project_client.agents.create_version( - agent_name=agent_name, - definition=HostedAgentDefinition( - cpu="0.5", - memory="1Gi", - image=image, - container_protocol_versions=[ - ProtocolVersionRecord(protocol="responses", version="1.0.0"), - ], - ), - metadata={"enableVnextExperience": "true"}, - ) - print(f"Agent created (name: {agent.name}, version: {agent.version})") - - await wait_for_agent_version_active_async( - project_client=project_client, - agent_name=agent_name, - agent_version=agent.version, - ) - - session = await project_client.beta.agents.create_session( - agent_name=agent_name, - isolation_key=isolation_key, - version_indicator=VersionRefIndicator(agent_version=agent.version), +) -> AgentVersionDetails: + async for version in project_client.agents.list_versions(agent_name=agent_name, order="desc"): + if version.status == "active": + return version + + raise RuntimeError( + f"No active version found for hosted agent '{agent_name}'. " + "Create or activate a version before running this sample." ) - print(f"Session created (id: {session.agent_session_id}, status: {session.status})") - - try: - yield agent.version, session.agent_session_id - finally: - await project_client.beta.agents.delete_session( - agent_name=agent_name, - session_id=session.agent_session_id, - isolation_key=isolation_key, - ) - print(f"Session with id: {session.agent_session_id} deleted.") - - await project_client.agents.delete_version(agent_name=agent_name, agent_version=agent.version) - print(f"Agent version {agent.version} deleted.") diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py new file mode 100644 index 000000000000..40ef3c3cf6a4 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/rbac_util.py @@ -0,0 +1,252 @@ +import uuid +from typing import Any, cast +from urllib.parse import urlparse + +from azure.core.credentials import TokenCredential +from azure.core.credentials_async import AsyncTokenCredential +from azure.core.exceptions import ResourceNotFoundError +from azure.mgmt.authorization import AuthorizationManagementClient, models as authorization_models +from azure.mgmt.authorization.aio import AuthorizationManagementClient as AsyncAuthorizationManagementClient +from azure.mgmt.resource import ResourceManagementClient +from azure.mgmt.resource.resources.aio import ResourceManagementClient as AsyncResourceManagementClient +from azure.ai.projects.models import AgentVersionDetails + +AZURE_AI_USER_ROLE_DEFINITION_GUID = "53ca6127-db72-4b80-b1b0-d745d6d5456d" + + +def _extract_resource_group_name(resource_id: str) -> str: + parts = resource_id.strip("/").split("/") + for index, part in enumerate(parts): + if part.lower() == "resourcegroups" and index + 1 < len(parts): + return parts[index + 1] + return "" + + +def _resolve_ai_account_resource_id( + credential: TokenCredential, + account_name: str, + project_name: str, + subscription_id: str, +) -> str: + resource_client = ResourceManagementClient(credential, subscription_id) + project_resources = resource_client.resources.list( + filter="resourceType eq 'Microsoft.CognitiveServices/accounts/projects'" + ) + + project_id_segment = f"/accounts/{account_name}/projects/{project_name}".lower() + matching_projects = [ + resource for resource in project_resources if resource.id and project_id_segment in resource.id.lower() + ] + if not matching_projects: + raise RuntimeError(f"Could not locate Foundry project '{project_name}' in subscription '{subscription_id}'.") + + if not matching_projects[0].id: + raise RuntimeError("Foundry project resource ID is empty.") + resource_group_name = _extract_resource_group_name(matching_projects[0].id) + account_resources = resource_client.resources.list_by_resource_group( + resource_group_name=resource_group_name, + filter="resourceType eq 'Microsoft.CognitiveServices/accounts'", + ) + + account_matches = [resource.id for resource in account_resources if resource.name == account_name and resource.id] + if not account_matches: + raise RuntimeError( + f"Could not locate Azure AI account '{account_name}' in resource group '{resource_group_name}'." + ) + return account_matches[0] + + +def _ensure_agent_identity_rbac_with_role_id( + credential: TokenCredential, principal_id: str, scope_resource_id: str, subscription_id: str, role_id: str +) -> tuple[bool, str]: + authorization_client = AuthorizationManagementClient(credential, subscription_id) + role_definition_id = f"/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_id}" + role_assignment_name = str( + uuid.uuid5( + uuid.NAMESPACE_URL, + f"{scope_resource_id}|{principal_id}|{role_definition_id}", + ) + ) + + try: + authorization_client.role_assignments.get(scope_resource_id, role_assignment_name) + print(f"Azure AI User role already assigned to principal {principal_id}.") + return False, role_assignment_name + except ResourceNotFoundError: + pass + + create_parameters_kwargs = cast( + dict[str, Any], + { + "role_definition_id": role_definition_id, + "principal_id": principal_id, + "principal_type": authorization_models.PrincipalType.SERVICE_PRINCIPAL, + }, + ) + parameters = authorization_models.RoleAssignmentCreateParameters(**create_parameters_kwargs) + + authorization_client.role_assignments.create(scope_resource_id, role_assignment_name, parameters) + print(f"Assigned Azure AI User role to principal {principal_id} at scope {scope_resource_id}.") + return True, role_assignment_name + + +def ensure_agent_identity_rbac( + agent: AgentVersionDetails, + credential: TokenCredential, + subscription_id: str, + foundry_project_endpoint: str, +) -> None: + """Ensure the hosted agent identity has Azure AI User role on the Azure AI account. + + This resolves the Azure AI account resource ID from the Foundry project endpoint, + reads the hosted agent managed identity principal ID from ``agent``, and + creates a deterministic role assignment for the Azure AI User role if one does not + already exist. + + :param agent: Agent version details containing ``instance_identity``. + :type agent: ~azure.ai.projects.models.AgentVersionDetails + :param credential: Credential used for Azure Resource Manager authorization calls. + :type credential: ~azure.core.credentials.TokenCredential + :param subscription_id: Azure subscription ID containing the Foundry project/account. + :type subscription_id: str + :param foundry_project_endpoint: Foundry project endpoint in the format + ``https://.services.ai.azure.com/api/projects/``. + :type foundry_project_endpoint: str + :raises RuntimeError: If the agent identity principal ID is unavailable, or if the + account/project resources cannot be resolved. + :raises ~azure.core.exceptions.HttpResponseError: If role assignment creation fails + for reasons other than an existing assignment. + """ + if not agent.instance_identity or not agent.instance_identity.principal_id: + raise RuntimeError("Agent instance_identity or principal_id is not available.") + principal_id = agent.instance_identity.principal_id + + account_name = urlparse(foundry_project_endpoint).hostname.split(".")[0] # type: ignore[union-attr] + project_name = foundry_project_endpoint.rstrip("/").split("/api/projects/")[1].split("/")[0] + scope_resource_id = _resolve_ai_account_resource_id(credential, account_name, project_name, subscription_id) + + _ensure_agent_identity_rbac_with_role_id( + credential=credential, + principal_id=principal_id, + scope_resource_id=scope_resource_id, + subscription_id=subscription_id, + role_id=AZURE_AI_USER_ROLE_DEFINITION_GUID, + ) + + +async def _resolve_ai_account_resource_id_async( + credential: AsyncTokenCredential, + account_name: str, + project_name: str, + subscription_id: str, +) -> str: + async with AsyncResourceManagementClient(credential, subscription_id) as resource_client: + project_id_segment = f"/accounts/{account_name}/projects/{project_name}".lower() + matching_projects = [] + async for resource in resource_client.resources.list( + filter="resourceType eq 'Microsoft.CognitiveServices/accounts/projects'" + ): + if resource.id and project_id_segment in resource.id.lower(): + matching_projects.append(resource) + if not matching_projects: + raise RuntimeError( + f"Could not locate Foundry project '{project_name}' in subscription '{subscription_id}'." + ) + + if not matching_projects[0].id: + raise RuntimeError("Foundry project resource ID is empty.") + resource_group_name = _extract_resource_group_name(matching_projects[0].id) + + account_matches = [] + async for resource in resource_client.resources.list_by_resource_group( + resource_group_name=resource_group_name, + filter="resourceType eq 'Microsoft.CognitiveServices/accounts'", + ): + if resource.name == account_name and resource.id: + account_matches.append(resource.id) + if not account_matches: + raise RuntimeError( + f"Could not locate Azure AI account '{account_name}' in resource group '{resource_group_name}'." + ) + return account_matches[0] + + +async def _ensure_agent_identity_rbac_with_role_id_async( + credential: AsyncTokenCredential, + principal_id: str, + scope_resource_id: str, + subscription_id: str, + role_id: str, +) -> tuple[bool, str]: + async with AsyncAuthorizationManagementClient(credential, subscription_id) as authorization_client: + role_definition_id = ( + f"/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_id}" + ) + role_assignment_name = str( + uuid.uuid5( + uuid.NAMESPACE_URL, + f"{scope_resource_id}|{principal_id}|{role_definition_id}", + ) + ) + + try: + await authorization_client.role_assignments.get(scope_resource_id, role_assignment_name) + print(f"Azure AI User role already assigned to principal {principal_id}.") + return False, role_assignment_name + except ResourceNotFoundError: + pass + + create_parameters_kwargs = cast( + dict[str, Any], + { + "role_definition_id": role_definition_id, + "principal_id": principal_id, + "principal_type": authorization_models.PrincipalType.SERVICE_PRINCIPAL, + }, + ) + parameters = authorization_models.RoleAssignmentCreateParameters(**create_parameters_kwargs) + + await authorization_client.role_assignments.create(scope_resource_id, role_assignment_name, parameters) + print(f"Assigned Azure AI User role to principal {principal_id} at scope {scope_resource_id}.") + return True, role_assignment_name + + +async def ensure_agent_identity_rbac_async( + agent: AgentVersionDetails, + credential: AsyncTokenCredential, + subscription_id: str, + foundry_project_endpoint: str, +) -> None: + """Async variant of :func:`ensure_agent_identity_rbac`. + + :param agent: Agent version details containing ``instance_identity``. + :type agent: ~azure.ai.projects.models.AgentVersionDetails + :param credential: Async credential used for Azure Resource Manager authorization calls. + :type credential: ~azure.core.credentials_async.AsyncTokenCredential + :param subscription_id: Azure subscription ID containing the Foundry project/account. + :type subscription_id: str + :param foundry_project_endpoint: Foundry project endpoint in the format + ``https://.services.ai.azure.com/api/projects/``. + :type foundry_project_endpoint: str + :raises RuntimeError: If the agent identity principal ID is unavailable, or if the + account/project resources cannot be resolved. + :raises ~azure.core.exceptions.HttpResponseError: If role assignment creation fails + for reasons other than an existing assignment. + """ + if not agent.instance_identity or not agent.instance_identity.principal_id: + raise RuntimeError("Agent instance_identity or principal_id is not available.") + principal_id = agent.instance_identity.principal_id + + account_name = urlparse(foundry_project_endpoint).hostname.split(".")[0] # type: ignore[union-attr] + project_name = foundry_project_endpoint.rstrip("/").split("/api/projects/")[1].split("/")[0] + scope_resource_id = await _resolve_ai_account_resource_id_async( + credential, account_name, project_name, subscription_id + ) + + await _ensure_agent_identity_rbac_with_role_id_async( + credential=credential, + principal_id=principal_id, + scope_resource_id=scope_resource_id, + subscription_id=subscription_id, + role_id=AZURE_AI_USER_ROLE_DEFINITION_GUID, + ) diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint.py index 0833548e857e..82be3e7df1ce 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint.py @@ -6,7 +6,7 @@ """ DESCRIPTION: - This sample demonstrates how to create a Hosted Agent and Session, + This sample demonstrates how to use an existing Hosted Agent and create a Session, configure an Agent endpoint for Responses protocol, and invoke the OpenAI Responses API against that agent endpoint using the synchronous AIProjectClient. @@ -27,11 +27,10 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. + If you don't have a Hosted Agent, run `sample_create_hosted_agent.py` or + `sample_create_hosted_agent_from_code.py` first to create one as a prerequisite. """ import os @@ -42,18 +41,18 @@ from azure.ai.projects import AIProjectClient from azure.ai.projects.models import ( - AgentEndpoint, + AgentEndpointConfig, AgentEndpointProtocol, FixedRatioVersionSelectionRule, VersionSelector, ) -from hosted_agents_util import create_agent_and_session +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version load_dotenv() endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] -agent_name = "MySessionHostedAgent" +agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] with ( DefaultAzureCredential() as credential, @@ -62,33 +61,47 @@ credential=credential, allow_preview=True, ) as project_client, - create_agent_and_session(project_client, agent_name, image) as (agent, session), ): - # Configure endpoint routing so this agent name serves the created version. - # 100% of traffic is routed to the single created version. - endpoint_config = AgentEndpoint( - version_selector=VersionSelector( - version_selection_rules=[ - FixedRatioVersionSelectionRule(agent_version=agent.version, traffic_percentage=100), - ] - ), - protocols=[AgentEndpointProtocol.RESPONSES], - ) - patched_agent = project_client.beta.agents.patch_agent_details( - agent_name=agent_name, - agent_endpoint=endpoint_config, - ) - print(f"Agent endpoint configured for agent: {patched_agent.name}") + agent = get_latest_active_agent_version(project_client, agent_name) - # Create an OpenAI client bound to the agent endpoint. - openai_client = project_client.get_openai_client(agent_name=agent_name) - - # Call Responses API and bind the request to the created agent session. - response = openai_client.responses.create( - input="What is the size of France in square miles?", - extra_body={ - "agent_session_id": session.agent_session_id, - }, + session = project_client.beta.agents.create_session( + agent_name=agent_name, + version_indicator=VersionRefIndicator(agent_version=agent.version), ) - print(f"Response output: {response.output_text}") + print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + try: + # Configure endpoint routing so this agent name serves the created version. + # 100% of traffic is routed to the single created version. + endpoint_config = AgentEndpointConfig( + version_selector=VersionSelector( + version_selection_rules=[ + FixedRatioVersionSelectionRule(agent_version=agent.version, traffic_percentage=100), + ] + ), + protocols=[AgentEndpointProtocol.RESPONSES], + ) + + patched_agent = project_client.beta.agents.patch_agent_details( + agent_name=agent_name, + agent_endpoint=endpoint_config, + ) + print(f"Agent endpoint configured for agent: {patched_agent.name}") + + # Create an OpenAI client bound to the agent endpoint. + openai_client = project_client.get_openai_client(agent_name=agent_name) + + # Call Responses API and bind the request to the created agent session. + response = openai_client.responses.create( + input="What is the size of France in square miles?", + extra_body={ + "agent_session_id": session.agent_session_id, + }, + ) + print(f"Response output: {response.output_text}") + finally: + project_client.beta.agents.delete_session( + agent_name=agent_name, + session_id=session.agent_session_id, + ) + print(f"Session deleted (id: {session.agent_session_id})") diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint_async.py index 91a9d8ac2437..94649b7ad73a 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_agent_endpoint_async.py @@ -6,7 +6,7 @@ """ DESCRIPTION: - This sample demonstrates how to create a Hosted Agent and Session, + This sample demonstrates how to use an existing Hosted Agent and create a Session, configure an Agent endpoint for Responses protocol, and invoke the OpenAI Responses API against that agent endpoint using the asynchronous AIProjectClient. @@ -27,11 +27,10 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. + If you don't have a Hosted Agent, run `sample_create_hosted_agent_async.py` or + `sample_create_hosted_agent_from_code_async.py` first to create one as a prerequisite. """ import asyncio @@ -43,21 +42,21 @@ from azure.ai.projects.aio import AIProjectClient from azure.ai.projects.models import ( - AgentEndpoint, + AgentEndpointConfig, AgentEndpointProtocol, FixedRatioVersionSelectionRule, VersionSelector, ) -from hosted_agents_util import create_agent_and_session_async +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version_async load_dotenv() -endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] -agent_name = "MySessionHostedAgent" +async def main(): + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] -async def main() -> None: async with ( DefaultAzureCredential() as credential, AIProjectClient( @@ -65,35 +64,50 @@ async def main() -> None: credential=credential, allow_preview=True, ) as project_client, - create_agent_and_session_async(project_client, agent_name, image) as (agent_version, session_id), ): - # Configure endpoint routing so this agent name serves the created version. - # 100% of traffic is routed to the single created version. - endpoint_config = AgentEndpoint( - version_selector=VersionSelector( - version_selection_rules=[ - FixedRatioVersionSelectionRule(agent_version=agent_version, traffic_percentage=100), - ] - ), - protocols=[AgentEndpointProtocol.RESPONSES], - ) - patched_agent = await project_client.beta.agents.patch_agent_details( + agent = await get_latest_active_agent_version_async(project_client, agent_name) + + session = await project_client.beta.agents.create_session( agent_name=agent_name, - agent_endpoint=endpoint_config, + version_indicator=VersionRefIndicator(agent_version=agent.version), ) - print(f"Agent endpoint configured for agent: {patched_agent.name}") + print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + try: + # Configure endpoint routing so this agent name serves the created version. + # 100% of traffic is routed to the single created version. + endpoint_config = AgentEndpointConfig( + version_selector=VersionSelector( + version_selection_rules=[ + FixedRatioVersionSelectionRule(agent_version=agent.version, traffic_percentage=100), + ] + ), + protocols=[AgentEndpointProtocol.RESPONSES], + ) + + patched_agent = await project_client.beta.agents.patch_agent_details( + agent_name=agent_name, + agent_endpoint=endpoint_config, + ) + print(f"Agent endpoint configured for agent: {patched_agent.name}") + + # Create an OpenAI client bound to the agent endpoint. + openai_client = project_client.get_openai_client(agent_name=agent_name) - # Create an OpenAI client bound to the agent endpoint. - async with project_client.get_openai_client(agent_name=agent_name) as openai_client: # Call Responses API and bind the request to the created agent session. response = await openai_client.responses.create( input="What is the size of France in square miles?", extra_body={ - "agent_session_id": session_id, + "agent_session_id": session.agent_session_id, }, ) print(f"Response output: {response.output_text}") + finally: + await project_client.beta.agents.delete_session( + agent_name=agent_name, + session_id=session.agent_session_id, + ) + print(f"Session deleted (id: {session.agent_session_id})") if __name__ == "__main__": diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent.py new file mode 100644 index 000000000000..e3e9530626a1 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent.py @@ -0,0 +1,88 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + This sample demonstrates CRUD operations for Hosted Agent versions + using the synchronous AIProjectClient. + + This is the only hosted_agents sample that sets up agent identity RBAC + via `ensure_agent_identity_rbac`. + +USAGE: + python sample_create_hosted_agent.py + + Before running the sample: + + pip install "azure-ai-projects>=2.1.0" azure-mgmt-authorization azure-mgmt-resource python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_HOSTED_AGENT_NAME - The Hosted Agent name. + 3) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format + '/[:|@]'. + You can build a sample image from the `samples/hosted_agents/assets/echo-agent` folder. + 4) AZURE_SUBSCRIPTION_ID - Azure subscription ID where the + Azure AI account and project are deployed. +""" + +import os + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import HostedAgentDefinition, ProtocolVersionRecord +from hosted_agents_util import wait_for_agent_version_active +from rbac_util import ensure_agent_identity_rbac + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] +image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] +subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"] + + +with ( + DefaultAzureCredential() as credential, + AIProjectClient( + endpoint=endpoint, + credential=credential, + allow_preview=True, + ) as project_client, +): + created = project_client.agents.create_version( + agent_name=agent_name, + definition=HostedAgentDefinition( + cpu="0.5", + memory="1Gi", + image=image, + container_protocol_versions=[ + ProtocolVersionRecord(protocol="responses", version="1.0.0"), + ], + ), + metadata={"enableVnextExperience": "true"}, + ) + print(f"Created hosted agent version: {created.version}") + + wait_for_agent_version_active( + project_client=project_client, + agent_name=agent_name, + agent_version=created.version, + ) + + ensure_agent_identity_rbac( + agent=created, + credential=credential, + subscription_id=subscription_id, + foundry_project_endpoint=endpoint, + ) + + fetched = project_client.agents.get_version(agent_name=agent_name, agent_version=created.version) + print(f"Fetched hosted agent version: {fetched.version}, status: {fetched.status}") diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_async.py new file mode 100644 index 000000000000..fcdf109a15ed --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_async.py @@ -0,0 +1,94 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Async variant of `sample_create_hosted_agent.py`. Demonstrates CRUD + operations for Hosted Agent versions using the asynchronous AIProjectClient. + + This is the only hosted_agents async sample that sets up agent identity + RBAC via `ensure_agent_identity_rbac_async`. + +USAGE: + python sample_create_hosted_agent_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.1.0" aiohttp azure-mgmt-authorization azure-mgmt-resource python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_HOSTED_AGENT_NAME - The Hosted Agent name. + 3) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format + '/[:|@]'. + You can build a sample image from the `samples/hosted_agents/assets/echo-agent` folder. + 4) AZURE_SUBSCRIPTION_ID - Azure subscription ID where the + Azure AI account and project are deployed. +""" + +import asyncio +import os + +from dotenv import load_dotenv + +from azure.identity.aio import DefaultAzureCredential + +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import HostedAgentDefinition, ProtocolVersionRecord +from hosted_agents_util import wait_for_agent_version_active_async +from rbac_util import ensure_agent_identity_rbac_async + + +async def main() -> None: + load_dotenv() + + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] + image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] + subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"] + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient( + endpoint=endpoint, + credential=credential, + allow_preview=True, + ) as project_client, + ): + created = await project_client.agents.create_version( + agent_name=agent_name, + definition=HostedAgentDefinition( + cpu="0.5", + memory="1Gi", + image=image, + container_protocol_versions=[ + ProtocolVersionRecord(protocol="responses", version="1.0.0"), + ], + ), + metadata={"enableVnextExperience": "true"}, + ) + print(f"Created hosted agent version: {created.version}") + + await wait_for_agent_version_active_async( + project_client=project_client, + agent_name=agent_name, + agent_version=created.version, + ) + + await ensure_agent_identity_rbac_async( + agent=created, + credential=credential, + subscription_id=subscription_id, + foundry_project_endpoint=endpoint, + ) + + fetched = await project_client.agents.get_version(agent_name=agent_name, agent_version=created.version) + print(f"Fetched hosted agent version: {fetched.version}, status: {fetched.status}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py new file mode 100644 index 000000000000..cdd4a3396125 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code.py @@ -0,0 +1,127 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Upload a code zip as a new version of a code-based Hosted Agent, + poll for provisioning, and download it back to verify the round-trip. + + The dependency resolution mode is selected via the + `FOUNDRY_HOSTED_AGENT_REMOTE_BUILD` environment variable (default: `false`): + + * `false` (BUNDLED) — uploads `assets/echo-agent-prebuilt.zip`, which + bundles the agent source plus a `packages/` folder with Linux-built + dependencies, so the service skips pip entirely. + * `true` (REMOTE_BUILD) — uploads `assets/echo-agent.zip`, which contains + only the agent source plus `requirements.txt`; the service resolves + dependencies remotely from the public package index. + + The agent must already exist; create it with + `samples/hosted_agents/sample_create_hosted_agent.py`. + +USAGE: + python sample_create_hosted_agent_from_code.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the + Overview page of your Microsoft Foundry portal. + 2) FOUNDRY_HOSTED_AGENT_NAME - The Hosted Agent name. Must already exist. + 3) AZURE_SUBSCRIPTION_ID - Azure subscription ID where the Azure AI account + and project are deployed. + 4) FOUNDRY_HOSTED_AGENT_REMOTE_BUILD - Optional. Set to `true` to use + REMOTE_BUILD; defaults to `false` (BUNDLED). +""" + +import hashlib +import os +import tempfile +from pathlib import Path + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + CodeConfiguration, + CreateAgentVersionFromCodeContent, + CreateAgentVersionFromCodeMetadata, + HostedAgentDefinition, + ProtocolVersionRecord, +) + +from hosted_agents_util import select_echo_agent_code_zip, wait_for_agent_version_active +from rbac_util import ensure_agent_identity_rbac + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] +subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"] +use_remote_build = os.environ.get("FOUNDRY_HOSTED_AGENT_REMOTE_BUILD", "false").strip().lower() == "true" + +dependency_resolution, zip_filename, code_zip_bytes, code_zip_sha256 = select_echo_agent_code_zip(use_remote_build) + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, +): + content = CreateAgentVersionFromCodeContent( + metadata=CreateAgentVersionFromCodeMetadata( + description=f"Code-based hosted agent uploaded with dependency_resolution={dependency_resolution.value}.", + definition=HostedAgentDefinition( + cpu="0.5", + memory="1Gi", + code_configuration=CodeConfiguration( + runtime="python_3_12", + entry_point=["python", "main.py"], + dependency_resolution=dependency_resolution, + ), + protocol_versions=[ProtocolVersionRecord(protocol="responses", version="1.0.0")], + ), + ), + code=(zip_filename, code_zip_bytes, "application/zip"), + ) + + created = project_client.beta.agents.create_version_from_code( + agent_name=agent_name, + content=content, + code_zip_sha256=code_zip_sha256, + ) + print(f"Created code-based hosted agent version: {created.version}") + + wait_for_agent_version_active( + project_client=project_client, + agent_name=agent_name, + agent_version=created.version, + ) + + ensure_agent_identity_rbac( + agent=created, + credential=credential, + subscription_id=subscription_id, + foundry_project_endpoint=endpoint, + ) + + # Download the zip for the version we just created, streaming to a temp file. + version_zip_path = Path(tempfile.gettempdir()) / f"{agent_name}-{created.version}.zip" + sha = hashlib.sha256() + with open(version_zip_path, "wb") as f: + for chunk in project_client.beta.agents.download_code( + agent_name=agent_name, + agent_version=created.version, + ): + f.write(chunk) + sha.update(chunk) + downloaded_version_sha256 = sha.hexdigest() + print( + f"Downloaded version code zip to {version_zip_path}: {version_zip_path.stat().st_size} bytes, " + f"sha256={downloaded_version_sha256} (matches uploaded: {downloaded_version_sha256 == code_zip_sha256})" + ) diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py new file mode 100644 index 000000000000..cd05ad4b472e --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_create_hosted_agent_from_code_async.py @@ -0,0 +1,138 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Async variant of `sample_create_hosted_agent_from_code.py`. Uploads a code + zip as a new version of a code-based Hosted Agent, polls for provisioning, + and downloads it back to verify the round-trip. + + The dependency resolution mode is selected via the + `FOUNDRY_HOSTED_AGENT_REMOTE_BUILD` environment variable (default: `false`): + + * `false` (BUNDLED) — uploads `assets/echo-agent-prebuilt.zip`, which + bundles the agent source plus a `packages/` folder with Linux-built + dependencies, so the service skips pip entirely. + * `true` (REMOTE_BUILD) — uploads `assets/echo-agent.zip`, which contains + only the agent source plus `requirements.txt`; the service resolves + dependencies remotely from the public package index. + + The agent must already exist; create it with + `samples/hosted_agents/sample_create_hosted_agent_async.py`. + +USAGE: + python sample_create_hosted_agent_from_code_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" aiohttp python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the + Overview page of your Microsoft Foundry portal. + 2) FOUNDRY_HOSTED_AGENT_NAME - The Hosted Agent name. Must already exist. + 3) AZURE_SUBSCRIPTION_ID - Azure subscription ID where the Azure AI account + and project are deployed. + 4) FOUNDRY_HOSTED_AGENT_REMOTE_BUILD - Optional. Set to `true` to use + REMOTE_BUILD; defaults to `false` (BUNDLED). +""" + +import asyncio +import hashlib +import os +import tempfile +from pathlib import Path + +from dotenv import load_dotenv + +from azure.identity.aio import DefaultAzureCredential + +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import ( + CodeConfiguration, + CreateAgentVersionFromCodeContent, + CreateAgentVersionFromCodeMetadata, + HostedAgentDefinition, + ProtocolVersionRecord, +) + +from hosted_agents_util import select_echo_agent_code_zip, wait_for_agent_version_active_async +from rbac_util import ensure_agent_identity_rbac_async + + +async def main() -> None: + load_dotenv() + + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] + subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"] + use_remote_build = os.environ.get("FOUNDRY_HOSTED_AGENT_REMOTE_BUILD", "false").strip().lower() == "true" + + dependency_resolution, zip_filename, code_zip_bytes, code_zip_sha256 = select_echo_agent_code_zip(use_remote_build) + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + content = CreateAgentVersionFromCodeContent( + metadata=CreateAgentVersionFromCodeMetadata( + description=f"Code-based hosted agent uploaded with dependency_resolution={dependency_resolution.value}.", + definition=HostedAgentDefinition( + cpu="0.5", + memory="1Gi", + code_configuration=CodeConfiguration( + runtime="python_3_12", + entry_point=["python", "main.py"], + dependency_resolution=dependency_resolution, + ), + protocol_versions=[ProtocolVersionRecord(protocol="responses", version="1.0.0")], + ), + ), + code=(zip_filename, code_zip_bytes, "application/zip"), + ) + + created = await project_client.beta.agents.create_version_from_code( + agent_name=agent_name, + content=content, + code_zip_sha256=code_zip_sha256, + ) + print(f"Created code-based hosted agent version: {created.version}") + + await wait_for_agent_version_active_async( + project_client=project_client, + agent_name=agent_name, + agent_version=created.version, + ) + + # ensure_agent_identity_rbac_async uses async ARM management clients with the + # same async credential. + await ensure_agent_identity_rbac_async( + agent=created, + credential=credential, + subscription_id=subscription_id, + foundry_project_endpoint=endpoint, + ) + + # Download the zip for the version we just created, streaming to a temp file. + version_zip_path = Path(tempfile.gettempdir()) / f"{agent_name}-{created.version}.zip" + sha = hashlib.sha256() + version_stream = await project_client.beta.agents.download_code( + agent_name=agent_name, + agent_version=created.version, + ) + with open(version_zip_path, "wb") as f: + async for chunk in version_stream: + f.write(chunk) + sha.update(chunk) + downloaded_version_sha256 = sha.hexdigest() + print( + f"Downloaded version code zip to {version_zip_path}: {version_zip_path.stat().st_size} bytes, " + f"sha256={downloaded_version_sha256} (matches uploaded: {downloaded_version_sha256 == code_zip_sha256})" + ) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream.py index e2658265cbb7..8957839ec8f9 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream.py @@ -6,31 +6,34 @@ """ DESCRIPTION: - This sample demonstrates how to stream hosted agent session logs - using `project_client.beta.agents.get_session_log_stream` with the - synchronous AIProjectClient. + This sample demonstrates how to stream hosted agent session logs + using `project_client.beta.agents.get_session_log_stream` with the + synchronous AIProjectClient. - Sessions only work with Hosted Agents. + Sessions only work with Hosted Agents. - Session and log stream operations are currently preview features. - In the Python SDK, you access these operations via - `project_client.beta.agents`. + Session and log stream operations are currently preview features. + In the Python SDK, you access these operations via + `project_client.beta.agents`. USAGE: - python sample_session_log_stream.py + python sample_session_log_stream.py - Before running the sample: + Before running the sample: - pip install "azure-ai-projects>=2.1.0" python-dotenv + pip install "azure-ai-projects>=2.1.0" python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview - page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview + page of your Microsoft Foundry portal. + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. + + If you don't have a Hosted Agent, run `sample_create_hosted_agent.py` or + `sample_create_hosted_agent_from_code.py` first to create one as a prerequisite. + + NOTE: This sample assumes the Foundry project and Azure AI account are in the + same resource group. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. """ import os @@ -41,18 +44,18 @@ from azure.ai.projects import AIProjectClient from azure.ai.projects.models import ( - AgentEndpoint, + AgentEndpointConfig, AgentEndpointProtocol, FixedRatioVersionSelectionRule, VersionSelector, ) -from hosted_agents_util import create_agent_and_session +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version load_dotenv() endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] -agent_name = "MySessionHostedAgent" +agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] def _iter_sse_frames(stream, max_log_events: int): @@ -91,25 +94,32 @@ def _iter_sse_frames(stream, max_log_events: int): credential=credential, allow_preview=True, ) as project_client, - create_agent_and_session(project_client, agent_name, image) as (agent, session), + project_client.get_openai_client(agent_name=agent_name) as openai_client, ): - endpoint_config = AgentEndpoint( - version_selector=VersionSelector( - version_selection_rules=[ - FixedRatioVersionSelectionRule(agent_version=agent.version, traffic_percentage=100), - ] - ), - protocols=[AgentEndpointProtocol.RESPONSES], - ) - - project_client.beta.agents.patch_agent_details( + agent = get_latest_active_agent_version(project_client, agent_name) + session = project_client.beta.agents.create_session( agent_name=agent_name, - agent_endpoint=endpoint_config, + version_indicator=VersionRefIndicator(agent_version=agent.version), ) - print(f"Agent endpoint configured for agent: {agent_name}") - input_text = "Say hello in one short sentence." + print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + try: + endpoint_config = AgentEndpointConfig( + version_selector=VersionSelector( + version_selection_rules=[ + FixedRatioVersionSelectionRule(agent_version=agent.version, traffic_percentage=100), + ] + ), + protocols=[AgentEndpointProtocol.RESPONSES], + ) + + project_client.beta.agents.patch_agent_details( + agent_name=agent_name, + agent_endpoint=endpoint_config, + ) + + print(f"Agent endpoint configured for agent: {agent_name}") + input_text = "Say hello in one short sentence." - with project_client.get_openai_client(agent_name=agent_name) as openai_client: response = openai_client.responses.create( input=input_text, extra_body={ @@ -118,12 +128,18 @@ def _iter_sse_frames(stream, max_log_events: int): ) print(f"Response output: {response.output_text}") - print("Streaming session logs...") - raw_stream = project_client.beta.agents.get_session_log_stream( - agent_name=agent_name, - agent_version=agent.version, - session_id=session.agent_session_id, - ) - for frame in _iter_sse_frames(raw_stream, max_log_events=30): - print(f"SSE event: {frame.get('event')}") - print(f"SSE data: {frame.get('data')}\n") + print("Streaming session logs...") + raw_stream = project_client.beta.agents.get_session_log_stream( + agent_name=agent_name, + agent_version=agent.version, + session_id=session.agent_session_id, + ) + for frame in _iter_sse_frames(raw_stream, max_log_events=30): + print(f"SSE event: {frame.get('event')}") + print(f"SSE data: {frame.get('data')}\n") + finally: + project_client.beta.agents.delete_session( + agent_name=agent_name, + session_id=session.agent_session_id, + ) + print(f"Session deleted (id: {session.agent_session_id})") diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream_async.py index aeafaf39b7ae..3c2fe3bfa3d9 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream_async.py @@ -26,11 +26,14 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. + + If you don't have a Hosted Agent, run `sample_create_hosted_agent_async.py` or + `sample_create_hosted_agent_from_code_async.py` first to create one as a prerequisite. + + NOTE: This sample assumes the Foundry project and Azure AI account are in the + same resource group. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. """ import asyncio @@ -42,21 +45,47 @@ from azure.ai.projects.aio import AIProjectClient from azure.ai.projects.models import ( - AgentEndpoint, + AgentEndpointConfig, AgentEndpointProtocol, FixedRatioVersionSelectionRule, VersionSelector, ) -from hosted_agents_util import create_agent_and_session_async +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version_async load_dotenv() -endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] -agent_name = "MySessionHostedAgent" + +def _iter_sse_frames(stream, max_log_events: int): + event_count = 0 + buffer = "" + + for chunk in stream: + buffer += chunk.decode("utf-8", errors="replace") + + while "\n\n" in buffer: + frame, buffer = buffer.split("\n\n", 1) + event_name = None + data_lines = [] + + for line in frame.splitlines(): + if line.startswith("event: "): + event_name = line[7:] + elif line.startswith("data: "): + data_lines.append(line[6:]) + + if data_lines or event_name: + event_count += 1 + yield { + "event": event_name, + "data": "\n".join(data_lines), + } + + if event_count >= max_log_events: + return -async def _iter_sse_frames(stream, max_log_events: int): +async def _iter_sse_frames_async(stream, max_log_events: int): event_count = 0 buffer = "" @@ -85,7 +114,10 @@ async def _iter_sse_frames(stream, max_log_events: int): return -async def main() -> None: +async def main(): + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] + async with ( DefaultAzureCredential() as credential, AIProjectClient( @@ -93,43 +125,55 @@ async def main() -> None: credential=credential, allow_preview=True, ) as project_client, - create_agent_and_session_async(project_client, agent_name, image) as (agent_version, session_id), ): - endpoint_config = AgentEndpoint( - version_selector=VersionSelector( - version_selection_rules=[ - FixedRatioVersionSelectionRule(agent_version=agent_version, traffic_percentage=100), - ] - ), - protocols=[AgentEndpointProtocol.RESPONSES], - ) - - await project_client.beta.agents.patch_agent_details( + agent = await get_latest_active_agent_version_async(project_client, agent_name) + session = await project_client.beta.agents.create_session( agent_name=agent_name, - agent_endpoint=endpoint_config, + version_indicator=VersionRefIndicator(agent_version=agent.version), ) - print(f"Agent endpoint configured for agent: {agent_name}") - input_text = "Say hello in one short sentence." + print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + try: + endpoint_config = AgentEndpointConfig( + version_selector=VersionSelector( + version_selection_rules=[ + FixedRatioVersionSelectionRule(agent_version=agent.version, traffic_percentage=100), + ] + ), + protocols=[AgentEndpointProtocol.RESPONSES], + ) + + await project_client.beta.agents.patch_agent_details( + agent_name=agent_name, + agent_endpoint=endpoint_config, + ) + + print(f"Agent endpoint configured for agent: {agent_name}") + input_text = "Say hello in one short sentence." - async with project_client.get_openai_client(agent_name=agent_name) as openai_client: + openai_client = project_client.get_openai_client(agent_name=agent_name) response = await openai_client.responses.create( input=input_text, extra_body={ - "agent_session_id": session_id, + "agent_session_id": session.agent_session_id, }, ) print(f"Response output: {response.output_text}") - print("Streaming session logs...") - raw_stream = await project_client.beta.agents.get_session_log_stream( - agent_name=agent_name, - agent_version=agent_version, - session_id=session_id, - ) - - async for frame in _iter_sse_frames(raw_stream, max_log_events=30): - print(f"SSE event: {frame.get('event')}") - print(f"SSE data: {frame.get('data')}\n") + print("Streaming session logs...") + raw_stream = await project_client.beta.agents.get_session_log_stream( + agent_name=agent_name, + agent_version=agent.version, + session_id=session.agent_session_id, + ) + async for frame in _iter_sse_frames_async(raw_stream, max_log_events=30): + print(f"SSE event: {frame.get('event')}") + print(f"SSE data: {frame.get('data')}\n") + finally: + await project_client.beta.agents.delete_session( + agent_name=agent_name, + session_id=session.agent_session_id, + ) + print(f"Session deleted (id: {session.agent_session_id})") if __name__ == "__main__": diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud.py index 5a840d7d0df1..5ef49160a3fb 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud.py @@ -24,11 +24,17 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. + If you don't have a Hosted Agent, run `sample_create_hosted_agent.py` or + `sample_create_hosted_agent_from_code.py` first to create one as a prerequisite. + +SDK FUNCTIONS: + - project_client.agents.list_versions: resolves the active version for the existing hosted agent. + - project_client.beta.agents.create_session: creates a session for the agent. + - project_client.beta.agents.get_session: retrieves a session by ID. + - project_client.beta.agents.list_sessions: lists sessions for an agent. + - project_client.beta.agents.delete_session: deletes a session by ID. """ import os @@ -38,13 +44,13 @@ from azure.identity import DefaultAzureCredential from azure.ai.projects import AIProjectClient -from azure.ai.projects.models import HostedAgentDefinition, VersionRefIndicator, ProtocolVersionRecord -from hosted_agents_util import wait_for_agent_version_active +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version load_dotenv() endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] +agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] with ( DefaultAzureCredential() as credential, @@ -54,39 +60,12 @@ allow_preview=True, ) as project_client, ): - agent_name = "MySessionHostedAgent" - - # Create an agent version to back the session - agent = project_client.agents.create_version( - agent_name=agent_name, - definition=HostedAgentDefinition( - cpu="0.5", - memory="1Gi", - image=image, - container_protocol_versions=[ - ProtocolVersionRecord(protocol="responses", version="1.0.0"), - ], - ), - metadata={"enableVnextExperience": "true"}, - ) - print(f"Agent created (name: {agent.name}, version: {agent.version})") - - wait_for_agent_version_active( - project_client=project_client, - agent_name=agent_name, - agent_version=agent.version, - ) - - isolation_key = "sample-isolation-key" - - # Create a session for the agent - print(f"Creating {3} sessions for the agent...") + agent = get_latest_active_agent_version(project_client, agent_name) session = project_client.beta.agents.create_session( agent_name=agent_name, - isolation_key=isolation_key, version_indicator=VersionRefIndicator(agent_version=agent.version), ) - print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + print(f"Created session (id: {session.agent_session_id}, status: {session.status})") # Retrieve the session by its ID fetched = project_client.beta.agents.get_session( @@ -102,11 +81,8 @@ for item in sessions: print(f" - {item.agent_session_id} (status: {item.status})") - # Delete the session - print(f"Deleting session with id: {session.agent_session_id}...") project_client.beta.agents.delete_session( agent_name=agent_name, session_id=session.agent_session_id, - isolation_key=isolation_key, ) - print(f"Session with id: {session.agent_session_id} deleted.") + print(f"Deleted session (id: {session.agent_session_id})") diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud_async.py index 49169702195b..82362b933488 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_crud_async.py @@ -24,11 +24,17 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. + If you don't have a Hosted Agent, run `sample_create_hosted_agent_async.py` or + `sample_create_hosted_agent_from_code_async.py` first to create one as a prerequisite. + +SDK FUNCTIONS: + - project_client.agents.list_versions: resolves the active version for the existing hosted agent. + - project_client.beta.agents.create_session: creates a session for the agent. + - project_client.beta.agents.get_session: retrieves a session by ID. + - project_client.beta.agents.list_sessions: lists sessions for an agent. + - project_client.beta.agents.delete_session: deletes a session by ID. """ import asyncio @@ -39,16 +45,16 @@ from azure.identity.aio import DefaultAzureCredential from azure.ai.projects.aio import AIProjectClient -from azure.ai.projects.models import HostedAgentDefinition, ProtocolVersionRecord, VersionRefIndicator -from hosted_agents_util import wait_for_agent_version_active_async +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version_async load_dotenv() -endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] +async def main(): + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] -async def main() -> None: async with ( DefaultAzureCredential() as credential, AIProjectClient( @@ -57,62 +63,32 @@ async def main() -> None: allow_preview=True, ) as project_client, ): - agent_name = "MySessionHostedAgent" - - # Create an agent version to back the session. - agent = await project_client.agents.create_version( + agent = await get_latest_active_agent_version_async(project_client, agent_name) + session = await project_client.beta.agents.create_session( agent_name=agent_name, - definition=HostedAgentDefinition( - cpu="0.5", - memory="1Gi", - image=image, - container_protocol_versions=[ - ProtocolVersionRecord(protocol="responses", version="v1"), - ], - ), - metadata={"enableVnextExperience": "true"}, + version_indicator=VersionRefIndicator(agent_version=agent.version), ) - print(f"Agent created (name: {agent.name}, version: {agent.version})") + print(f"Created session (id: {session.agent_session_id}, status: {session.status})") - await wait_for_agent_version_active_async( - project_client=project_client, + # Retrieve the session by its ID + fetched = await project_client.beta.agents.get_session( agent_name=agent_name, - agent_version=agent.version, + session_id=session.agent_session_id, ) + print(f"Retrieved session (id: {fetched.agent_session_id}, status: {fetched.status})") - isolation_key = "sample-isolation-key" - session = await project_client.beta.agents.create_session( + # List sessions for the agent + print("Listing sessions for the agent...") + sessions = project_client.beta.agents.list_sessions(agent_name=agent_name) + print("Sessions:") + async for item in sessions: + print(f" - {item.agent_session_id} (status: {item.status})") + + await project_client.beta.agents.delete_session( agent_name=agent_name, - isolation_key=isolation_key, - version_indicator=VersionRefIndicator(agent_version=agent.version), + session_id=session.agent_session_id, ) - print(f"Session created (id: {session.agent_session_id}, status: {session.status})") - - try: - fetched = await project_client.beta.agents.get_session( - agent_name=agent_name, - session_id=session.agent_session_id, - ) - print(f"Retrieved session (id: {fetched.agent_session_id}, status: {fetched.status})") - - print("Listing sessions for the agent...") - sessions = [] - async for item in project_client.beta.agents.list_sessions(agent_name=agent_name): - sessions.append(item) - print("Sessions:") - for item in sessions: - print(f" - {item.agent_session_id} (status: {item.status})") - finally: - print(f"Deleting session with id: {session.agent_session_id}...") - await project_client.beta.agents.delete_session( - agent_name=agent_name, - session_id=session.agent_session_id, - isolation_key=isolation_key, - ) - print(f"Session with id: {session.agent_session_id} deleted.") - - await project_client.agents.delete_version(agent_name=agent_name, agent_version=agent.version) - print(f"Agent version {agent.version} deleted.") + print(f"Deleted session (id: {session.agent_session_id})") if __name__ == "__main__": diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py index fa423e02c28c..3bc0a932d890 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download.py @@ -24,11 +24,10 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. + If you don't have a Hosted Agent, run `sample_create_hosted_agent.py` or + `sample_create_hosted_agent_from_code.py` first to create one as a prerequisite. """ import os @@ -38,12 +37,13 @@ from azure.identity import DefaultAzureCredential from azure.ai.projects import AIProjectClient -from hosted_agents_util import create_agent_and_session +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version load_dotenv() endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] +agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] # Construct the paths to the data folder and data file used in this sample script_dir = os.path.dirname(os.path.abspath(__file__)) @@ -62,10 +62,13 @@ allow_preview=True, ) as project_client, ): - agent_name = "MySessionHostedAgent" - - with create_agent_and_session(project_client, agent_name, image) as (_, session): - + agent = get_latest_active_agent_version(project_client, agent_name) + session = project_client.beta.agents.create_session( + agent_name=agent_name, + version_indicator=VersionRefIndicator(agent_version=agent.version), + ) + print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + try: # Upload and list session files project_client.beta.agents.upload_session_file( agent_name=agent_name, @@ -115,3 +118,9 @@ agent_session_id=session.agent_session_id, path=remote_file_path2, ) + finally: + project_client.beta.agents.delete_session( + agent_name=agent_name, + session_id=session.agent_session_id, + ) + print(f"Session deleted (id: {session.agent_session_id})") diff --git a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py index 0f37627826d1..cc9ad46eb64f 100644 --- a/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py +++ b/sdk/ai/azure-ai-projects/samples/hosted_agents/sample_sessions_files_upload_download_async.py @@ -6,8 +6,8 @@ """ DESCRIPTION: - This sample demonstrates how to perform session file upload, list, download, - and delete operations using the asynchronous AIProjectClient. + This sample demonstrates how to perform CRUD operations on agent Sessions + using the asynchronous AIProjectClient. Sessions only work with Hosted Agents. @@ -24,11 +24,10 @@ Set these environment variables with your own values: 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint, as found in the Overview page of your Microsoft Foundry portal. - 2) FOUNDRY_AGENT_CONTAINER_IMAGE - The Hosted Agent container image in the format '/[:|@]' + 2) FOUNDRY_HOSTED_AGENT_NAME - The name of an existing Hosted Agent. - You can build and push an example image from - `samples/hosted_agents/assets/responses-echo-agent` and use that image value - for `FOUNDRY_AGENT_CONTAINER_IMAGE`. + If you don't have a Hosted Agent, run `sample_create_hosted_agent_async.py` or + `sample_create_hosted_agent_from_code_async.py` first to create one as a prerequisite. """ import asyncio @@ -39,23 +38,24 @@ from azure.identity.aio import DefaultAzureCredential from azure.ai.projects.aio import AIProjectClient -from hosted_agents_util import create_agent_and_session_async +from azure.ai.projects.models import VersionRefIndicator +from hosted_agents_util import get_latest_active_agent_version_async load_dotenv() -endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] -image = os.environ["FOUNDRY_AGENT_CONTAINER_IMAGE"] -# Construct the paths to the data folder and data file used in this sample -script_dir = os.path.dirname(os.path.abspath(__file__)) -data_folder = os.path.join(script_dir, "assets") -data_file1 = os.path.join(data_folder, "data_file1.txt") -data_file2 = os.path.join(data_folder, "data_file2.txt") -remote_file_path1 = "/remote/data_file1.txt" -remote_file_path2 = "/remote/data_file2.txt" +async def main(): + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_HOSTED_AGENT_NAME"] + # Construct the paths to the data folder and data file used in this sample + script_dir = os.path.dirname(os.path.abspath(__file__)) + data_folder = os.path.join(script_dir, "assets") + data_file1 = os.path.join(data_folder, "data_file1.txt") + data_file2 = os.path.join(data_folder, "data_file2.txt") + remote_file_path1 = "/remote/data_file1.txt" + remote_file_path2 = "/remote/data_file2.txt" -async def main() -> None: async with ( DefaultAzureCredential() as credential, AIProjectClient( @@ -64,12 +64,17 @@ async def main() -> None: allow_preview=True, ) as project_client, ): - agent_name = "MySessionHostedAgent" - - async with create_agent_and_session_async(project_client, agent_name, image) as (_, session_id): + agent = await get_latest_active_agent_version_async(project_client, agent_name) + session = await project_client.beta.agents.create_session( + agent_name=agent_name, + version_indicator=VersionRefIndicator(agent_version=agent.version), + ) + print(f"Session created (id: {session.agent_session_id}, status: {session.status})") + try: + # Upload and list session files await project_client.beta.agents.upload_session_file( agent_name=agent_name, - session_id=session_id, + session_id=session.agent_session_id, content_or_file_path=data_file1, path=remote_file_path1, ) @@ -77,7 +82,7 @@ async def main() -> None: print(f"Uploading session file: {data_file2} -> {remote_file_path2}") await project_client.beta.agents.upload_session_file( agent_name=agent_name, - session_id=session_id, + session_id=session.agent_session_id, content_or_file_path=data_file2, path=remote_file_path2, ) @@ -85,35 +90,42 @@ async def main() -> None: print("Listing session files for the session at path '.'...") files = await project_client.beta.agents.get_session_files( agent_name=agent_name, - agent_session_id=session_id, + agent_session_id=session.agent_session_id, path="/remote", ) for entry in files.entries: print(f" - name={entry.name}, size={entry.size}, is_directory={entry.is_directory}") print(f"Downloading and printing content from '{remote_file_path1}'") - download_stream = await project_client.beta.agents.download_session_file( + content_bytes = b"" + async for chunk in await project_client.beta.agents.download_session_file( agent_name=agent_name, - agent_session_id=session_id, + agent_session_id=session.agent_session_id, path=remote_file_path1, - ) - content_bytes = b"".join([chunk async for chunk in download_stream]) + ): + content_bytes += chunk file_content = content_bytes.decode("utf-8", errors="replace") print(f"Session file content ({remote_file_path1}):\n{file_content}") print(f"Deleting session file at path: {remote_file_path1}...") await project_client.beta.agents.delete_session_file( agent_name=agent_name, - agent_session_id=session_id, + agent_session_id=session.agent_session_id, path=remote_file_path1, ) print(f"Deleting session file at path: {remote_file_path2}...") await project_client.beta.agents.delete_session_file( agent_name=agent_name, - agent_session_id=session_id, + agent_session_id=session.agent_session_id, path=remote_file_path2, ) + finally: + await project_client.beta.agents.delete_session( + agent_name=agent_name, + session_id=session.agent_session_id, + ) + print(f"Session deleted (id: {session.agent_session_id})") if __name__ == "__main__": diff --git a/sdk/ai/azure-ai-projects/samples/indexes/sample_indexes.py b/sdk/ai/azure-ai-projects/samples/indexes/sample_indexes.py index 04ac684cb8d3..e323d540c829 100644 --- a/sdk/ai/azure-ai-projects/samples/indexes/sample_indexes.py +++ b/sdk/ai/azure-ai-projects/samples/indexes/sample_indexes.py @@ -45,7 +45,6 @@ project_client.get_openai_client() as openai_client, ): - # [START indexes_sample] print(f"Create Index `{index_name}` with version `{index_version}`, referencing an existing AI Search resource:") index = project_client.indexes.create_or_update( name=index_name, @@ -68,4 +67,3 @@ print(f"Delete Index `{index_name}` version `{index_version}`:") project_client.indexes.delete(name=index_name, version=index_version) - # [END indexes_sample] 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 new file mode 100644 index 000000000000..274255c046e2 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.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.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. + +USAGE: + 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 `create` 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 `create`." + ) + model = project_client.beta.models.create( + name=model_name, + version=model_version, + source=data_folder, + weight_type=FoundryModelWeightType.FULL_WEIGHT, + description="Sample model registered from sample_models_basic.py", + tags={"source": "sample_models_basic.py"}, + ) + 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(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): + 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, + credential_request=ModelCredentialRequest(blob_uri=model.blob_uri), + ) + print(f"Credentials (type: {type(creds).__name__})") + + 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_basic.py", "updated": "true"}, + ), + ) + 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_basic_async.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py new file mode 100644 index 000000000000..d0fd70bde4a5 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_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`, `pending_create_version`, + `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + + 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: + + 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) `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_basic_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, + ModelPendingUploadRequest, + ModelVersion, + 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, + pending_upload_request=ModelPendingUploadRequest( + 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: pending_create_version(name=`{model_name}`, version=`{model_version}`)") + await project_client.beta.models.pending_create_version( + name=model_name, + version=model_version, + model_version=ModelVersion( + blob_uri=container_blob_uri, + weight_type=FoundryModelWeightType.FULL_WEIGHT, + description="Sample model registered from sample_models_basic_async.py", + tags={"source": "sample_models_basic_async.py"}, + ), + ) + + # `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 + 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 pending_create_version." + ) + await asyncio.sleep(2.0) + 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): + 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, + credential_request=ModelCredentialRequest(blob_uri=model.blob_uri), + ) + 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( + name=model_name, + version=model_version, + body=UpdateModelVersionRequest( + description="Updated description", + tags={"source": "sample_models_basic_async.py", "updated": "true"}, + ), + ) + 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) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_create_and_poll.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_create_and_poll.py new file mode 100644 index 000000000000..7e38fefa2038 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_create_and_poll.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 + `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`: + + 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) `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. + + 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_create_and_poll.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, + ModelPendingUploadRequest, + ModelVersion, + 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, + pending_upload_request=ModelPendingUploadRequest( + 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: pending_create_version(name=`{model_name}`, version=`{model_version}`)") + project_client.beta.models.pending_create_version( + name=model_name, + version=model_version, + model_version=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"}, + ), + ) + + # `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 + 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 pending_create_version." + ) + 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) diff --git a/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team.py b/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team.py index eebf4356fee0..31f25a25636c 100644 --- a/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team.py +++ b/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team.py @@ -49,7 +49,6 @@ AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): - # [START red_team_sample] print("Creating a Red Team scan for direct model testing") # Create target configuration for testing an Azure OpenAI model @@ -81,4 +80,3 @@ print("Listing all Red Team scans") for scan in project_client.beta.red_teams.list(): print(f"Found scan: {scan.name}, Status: {scan.status}") - # [END red_team_sample] diff --git a/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team_async.py b/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team_async.py index cd7969dc6b9c..60201ef8fd7d 100644 --- a/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team_async.py +++ b/sdk/ai/azure-ai-projects/samples/red_team/sample_red_team_async.py @@ -53,7 +53,6 @@ async def sample_red_team_async() -> None: DefaultAzureCredential() as credential, AIProjectClient(endpoint=endpoint, credential=credential) as project_client, ): - # [START red_team_sample] print("Creating a Red Team scan for direct model testing") # Create target configuration for testing an Azure OpenAI model @@ -85,7 +84,6 @@ async def sample_red_team_async() -> None: print("Listing all Red Team scans") async for scan in project_client.beta.red_teams.list(): print(f"Found scan: {scan.name}, Status: {scan.status}") - # [END red_team_sample] if __name__ == "__main__": diff --git a/sdk/ai/azure-ai-projects/tests/agents/telemetry/test_non_recording_span.py b/sdk/ai/azure-ai-projects/tests/agents/telemetry/test_non_recording_span.py new file mode 100644 index 000000000000..c64b0288bdb1 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/telemetry/test_non_recording_span.py @@ -0,0 +1,202 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +""" +Tests verifying that instrumentors correctly skip non-recording spans. + +When a span is not recording, the instrumentor must not attempt to write +attributes or events to it. These tests use a mock span whose +``is_recording()`` returns False and whose mutation methods raise +``AssertionError`` if called, ensuring the guards work correctly. +""" + +import os +import json +import pytest +from unittest.mock import MagicMock, PropertyMock + +from azure.ai.projects.telemetry._ai_project_instrumentor import ( + _AIAgentsInstrumentorPreview, +) +from azure.ai.projects.telemetry._responses_instrumentor import ( + _ResponsesInstrumentorPreview, +) + + +def _make_non_recording_span(): + """Return a mock AbstractSpan wrapping a non-recording OTel span. + + * ``span_instance.is_recording()`` returns ``False`` + * ``span_instance.is_recording`` (the property/method) also returns ``False`` + so the guard correctly skips writes. + * Any call to ``add_event``, ``set_status``, ``record_exception`` or + ``set_attribute`` raises ``AssertionError``, catching any code path + that fails to check ``is_recording()`` properly. + """ + span_instance = MagicMock() + span_instance.is_recording = MagicMock(return_value=False) + span_instance.add_event = MagicMock(side_effect=AssertionError("add_event called on non-recording span")) + span_instance.set_status = MagicMock(side_effect=AssertionError("set_status called on non-recording span")) + span_instance.record_exception = MagicMock( + side_effect=AssertionError("record_exception called on non-recording span") + ) + + span = MagicMock() + span.span_instance = span_instance + span.add_attribute = MagicMock(side_effect=AssertionError("add_attribute called on non-recording span")) + return span + + +class TestNonRecordingSpanProjectInstrumentor: + """Verify _AIAgentsInstrumentorPreview skips non-recording spans.""" + + def test_add_message_event_skips_non_recording_span(self): + """_add_message_event should not write to a non-recording span.""" + instrumentor = _AIAgentsInstrumentorPreview() + span = _make_non_recording_span() + + # This must not raise; the guard should return early. + instrumentor._add_message_event(span, role="user", content="hello") + + def test_add_instructions_event_skips_non_recording_span(self): + """_add_instructions_event should not write to a non-recording span.""" + instrumentor = _AIAgentsInstrumentorPreview() + span = _make_non_recording_span() + + instrumentor._add_instructions_event(span, instructions="Be helpful", additional_instructions=None) + + def test_start_create_agent_span_skips_non_recording_span(self): + """start_create_agent_span should not write attributes to a non-recording span.""" + instrumentor = _AIAgentsInstrumentorPreview() + + # We need to patch start_span to return our non-recording span + from unittest.mock import patch + + non_recording_span = _make_non_recording_span() + + with patch( + "azure.ai.projects.telemetry._ai_project_instrumentor.start_span", + return_value=non_recording_span, + ): + result = instrumentor.start_create_agent_span( + server_address="test.openai.azure.com", + port=443, + model="gpt-4", + name="test-agent", + instructions="Be helpful", + ) + + # Should return the span but not have written any attributes/events to it + assert result is non_recording_span + non_recording_span.add_attribute.assert_not_called() + non_recording_span.span_instance.add_event.assert_not_called() + + +class TestNonRecordingSpanResponsesInstrumentor: + """Verify _ResponsesInstrumentorPreview skips non-recording spans.""" + + def test_set_span_attribute_safe_skips_non_recording_span(self): + """_set_span_attribute_safe should not write to a non-recording span.""" + instrumentor = _ResponsesInstrumentorPreview() + span = _make_non_recording_span() + + # This must not raise; the guard should return early. + instrumentor._set_span_attribute_safe(span, "test.key", "test_value") + + def test_start_responses_span_skips_non_recording_span(self): + """start_responses_span should not write attributes to a non-recording span.""" + instrumentor = _ResponsesInstrumentorPreview() + + from unittest.mock import patch + + non_recording_span = _make_non_recording_span() + + with patch( + "azure.ai.projects.telemetry._responses_instrumentor.start_span", + return_value=non_recording_span, + ): + result = instrumentor.start_responses_span( + server_address="test.openai.azure.com", + port=443, + model="gpt-4", + assistant_name="test-agent", + conversation_id="conv-123", + input_text="Hello", + ) + + assert result is non_recording_span + non_recording_span.add_attribute.assert_not_called() + non_recording_span.span_instance.add_event.assert_not_called() + + def test_start_create_conversation_span_skips_non_recording_span(self): + """start_create_conversation_span should not write to a non-recording span.""" + instrumentor = _ResponsesInstrumentorPreview() + + from unittest.mock import patch + + non_recording_span = _make_non_recording_span() + + with patch( + "azure.ai.projects.telemetry._responses_instrumentor.start_span", + return_value=non_recording_span, + ): + result = instrumentor.start_create_conversation_span( + server_address="test.openai.azure.com", + port=443, + ) + + assert result is non_recording_span + non_recording_span.add_attribute.assert_not_called() + non_recording_span.span_instance.add_event.assert_not_called() + + def test_start_list_conversation_items_span_skips_non_recording_span(self): + """start_list_conversation_items_span should not write to a non-recording span.""" + instrumentor = _ResponsesInstrumentorPreview() + + from unittest.mock import patch + + non_recording_span = _make_non_recording_span() + + with patch( + "azure.ai.projects.telemetry._responses_instrumentor.start_span", + return_value=non_recording_span, + ): + result = instrumentor.start_list_conversation_items_span( + server_address="test.openai.azure.com", + port=443, + conversation_id="conv-123", + ) + + assert result is non_recording_span + non_recording_span.add_attribute.assert_not_called() + non_recording_span.span_instance.add_event.assert_not_called() + + def test_add_tool_call_events_skips_non_recording_span(self): + """_add_tool_call_events should not write to a non-recording span.""" + instrumentor = _ResponsesInstrumentorPreview() + span = _make_non_recording_span() + + # Create a mock response with function call output + mock_response = MagicMock() + mock_output_item = MagicMock() + mock_output_item.type = "function_call" + mock_output_item.name = "get_weather" + mock_output_item.call_id = "call_123" + mock_output_item.arguments = '{"city": "Seattle"}' + mock_response.output = [mock_output_item] + + instrumentor._add_tool_call_events(span, mock_response) + + def test_add_conversation_item_event_skips_non_recording_span(self): + """_add_conversation_item_event should not write to a non-recording span.""" + instrumentor = _ResponsesInstrumentorPreview() + span = _make_non_recording_span() + + mock_item = MagicMock() + mock_item.id = "item_123" + mock_item.type = "message" + mock_item.role = "user" + mock_item.content = [] + + instrumentor._add_conversation_item_event(span, mock_item) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception.py b/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception.py index d013c33e9847..076351f49a78 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception.py @@ -10,7 +10,7 @@ from devtools_testutils import recorded_by_proxy, RecordedTransport from azure.core.exceptions import HttpResponseError from azure.ai.projects.models import WorkflowAgentDefinition -from azure.ai.projects.operations._patch_agents import _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE +from azure.ai.projects.models._patch import _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE # Minimal workflow YAML — the service rejects the request before validating the # definition, so the content only needs to be a non-empty string. diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception_async.py b/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception_async.py index a4ebac76ffa6..f60b7f38fa4c 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception_async.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_agent_create_version_exception_async.py @@ -11,7 +11,7 @@ from devtools_testutils import RecordedTransport from azure.core.exceptions import HttpResponseError from azure.ai.projects.models import WorkflowAgentDefinition -from azure.ai.projects.operations._patch_agents import _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE +from azure.ai.projects.models._patch import _PREVIEW_FEATURE_ADDED_ERROR_MESSAGE # Minimal workflow YAML — the service rejects the request before validating the # definition, so the content only needs to be a non-empty string. diff --git a/sdk/ai/azure-ai-projects/tests/conftest.py b/sdk/ai/azure-ai-projects/tests/conftest.py index a6dd76036377..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 @@ -181,6 +257,24 @@ def sanitize_url_paths(): regex=r"(?i)^Bearer\s+github_pat_[A-Za-z0-9_]+$", ) + # Sanitize raw Entra-ID JWTs (no "Bearer " prefix) passed via MCPTool.authorization + # to match the `fake_token` value the FakeTokenCredential returns during playback. + add_body_key_sanitizer( + json_path="$..authorization", + value="fake_token", + regex=r"^eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+$", + ) + + # Sanitize Cognitive Services / Foundry account hostnames inside request and + # response bodies (e.g. MCPTool.server_url built from FOUNDRY_PROJECT_ENDPOINT). + # URL-path sanitizers above already redact /accounts/, /projects/, etc., + # but the host is built into body fields and needs its own redaction so + # recordings match the playback FOUNDRY_PROJECT_ENDPOINT. + add_body_regex_sanitizer( + regex=r"https://[a-z0-9-]+\.services\.ai\.azure\.com", + value=f"https://{SanitizedValues.ACCOUNT_NAME}.services.ai.azure.com", + ) + # Sanitize Azure Blob account host while preserving container path and SAS shape. # This avoids creating inconsistent recordings where sasUri points to a different # container than the corresponding blob RequestUri entries. @@ -213,6 +307,11 @@ def sanitize_url_paths(): headers="x-stainless-arch, x-stainless-async, x-stainless-lang, x-stainless-os, x-stainless-package-version, x-stainless-read-timeout, x-stainless-retry-count, x-stainless-runtime, x-stainless-runtime-version" ) + # Strip Content-Encoding so playback doesn't try to decompress a body that the test-proxy + # has already stored decoded (notably brotli responses from openai endpoints which httpx + # would otherwise fail to decode -> UnicodeDecodeError). + add_remove_header_sanitizer(headers="Content-Encoding") + # Remove the following sanitizers since certain fields are needed in tests and are non-sensitive: # - AZSDK3493: $..name # - AZSDK3430: $..id 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 2c80a40f9902..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 @@ -39,11 +39,35 @@ "evaluators": "Evaluations=V1Preview", "insights": "Insights=V1Preview", "memory_stores": "MemoryStores=V1Preview", + "models": "Models=V1Preview", "red_teams": "RedTeams=V1Preview", + "routines": "Routines=V1Preview", "schedules": "Schedules=V1Preview", "toolboxes": "Toolboxes=V1Preview", "skills": "Skills=V1Preview", - "agents": "HostedAgents=V1Preview,AgentEndpoints=V1Preview", + "datasets": "DataGenerationJobs=V1Preview", + "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. @@ -58,7 +82,7 @@ # The test id is derived automatically from method_name. pytest.param( "agents.create_version", - "HostedAgents=V1Preview,WorkflowAgents=V1Preview,AgentEndpoints=V1Preview", + "HostedAgents=V1Preview,WorkflowAgents=V1Preview,AgentEndpoints=V1Preview,CodeAgents=V1Preview,ExternalAgents=V1Preview,AgentsOptimization=V1Preview", ), pytest.param( "evaluation_rules.create_or_update", 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 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..356a83d14d3e --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/models/test_models.py @@ -0,0 +1,141 @@ +# 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 ``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 +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_create -s + @servicePreparer() + @recorded_by_proxy + 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"] + 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_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", + 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" + + 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] 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] 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] 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_create] 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_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) + + # 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 ModelPendingUploadRequest, 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=ModelPendingUploadRequest( + 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..b92c0c6e54c1 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py @@ -0,0 +1,98 @@ +# 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. ``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 +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.create( + 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..d2c8dd6da57a --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py @@ -0,0 +1,440 @@ +# 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 ``create`` (mocking ``pending_upload``, ``pending_create_version`` +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") + + +# --------------------------------------------------------------------------- +# create 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 TestCreateVersionOrchestration: + @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() + + 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("pending_create_version") + assert kwargs["name"] == "my-model" + assert kwargs["version"] == "1" + 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" + 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, "pending_create_version", side_effect=fake_create_async), mock.patch.object( + ops, "get", side_effect=fake_get + ): + result = ops.create( + 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", "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") + 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, "pending_create_version", return_value=None), mock.patch.object(ops, "get", get_mock): + result = ops.create( + name="m", + version="1", + source=tmp_path, + wait_for_commit=False, + ) + + assert result is None + get_mock.assert_not_called() + + 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") + + 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, "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.create( + 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_models_create_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, "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", + 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.create( + name="m", + version="1", + source=tmp_path, + polling_timeout=1.0, + ) + + 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.create(name="m", version="1", source=ghost) + pending.assert_not_called() + + +# --------------------------------------------------------------------------- +# _validate_create_inputs +# --------------------------------------------------------------------------- + + +class TestValidateCreateVersionInputs: + @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_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_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_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_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_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_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_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_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_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.create(name="m", version="1", source=tmp_path) + pending.assert_not_called() diff --git a/sdk/ai/azure-ai-projects/tests/responses/openai_test_helpers.py b/sdk/ai/azure-ai-projects/tests/responses/openai_test_helpers.py new file mode 100644 index 000000000000..fbf3637291ea --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/responses/openai_test_helpers.py @@ -0,0 +1,69 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Shared helpers for unit-testing AIProjectClient.get_openai_client (sync and async). + +These helpers build lightweight client stubs that bypass the real ``__init__`` so unit +tests can target individual branches of ``get_openai_client`` without making any +network calls. +""" + +from typing import Optional +from unittest.mock import MagicMock + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient + +ENDPOINT = "https://myaccount.services.ai.azure.com/api/projects/myproject" +API_VERSION = "2025-01-01" + +# Patch targets used by tests to swap in mocked OpenAI/AsyncOpenAI constructors +# and bearer-token providers. +SYNC_OPENAI_PATCH = "azure.ai.projects._patch.OpenAI" +ASYNC_OPENAI_PATCH = "azure.ai.projects.aio._patch.AsyncOpenAI" +SYNC_TOKEN_PROVIDER_PATCH = "azure.ai.projects._patch.get_bearer_token_provider" +ASYNC_TOKEN_PROVIDER_PATCH = "azure.ai.projects.aio._patch.get_bearer_token_provider" + + +def make_sync_client( + allow_preview: bool = True, + console_logging: bool = False, + custom_user_agent: Optional[str] = None, +) -> AIProjectClient: + """Return a minimal sync AIProjectClient stub suitable for unit-testing get_openai_client.""" + client = AIProjectClient.__new__(AIProjectClient) + client._config = MagicMock() + client._config.endpoint = ENDPOINT + client._config.allow_preview = allow_preview + client._config.api_version = API_VERSION + client._config.credential = MagicMock() + client._console_logging_enabled = console_logging + client._custom_user_agent = custom_user_agent + return client + + +def make_async_client( + allow_preview: bool = True, + console_logging: bool = False, + custom_user_agent: Optional[str] = None, +) -> AsyncAIProjectClient: + """Return a minimal async AIProjectClient stub suitable for unit-testing get_openai_client.""" + client = AsyncAIProjectClient.__new__(AsyncAIProjectClient) + client._config = MagicMock() + client._config.endpoint = ENDPOINT + client._config.allow_preview = allow_preview + client._config.api_version = API_VERSION + client._config.credential = MagicMock() + client._console_logging_enabled = console_logging + client._custom_user_agent = custom_user_agent + return client + + +def mock_openai(user_agent: str = "openai/1.0"): + """Return ``(mock_class, mock_instance)`` where ``mock_class`` acts as the OpenAI constructor.""" + instance = MagicMock() + instance.user_agent = user_agent + mock_cls = MagicMock(return_value=instance) + return mock_cls, instance diff --git a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint.py b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint.py index 87aecf0a94fa..be5d6f429040 100644 --- a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint.py +++ b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint.py @@ -4,13 +4,26 @@ # Licensed under the MIT License. # ------------------------------------ """ -Unit tests for verifying the base_url of the OpenAI client returned by AIProjectClient.get_openai_client(). +Unit tests for verifying the base_url, default_query (api-version) and Foundry feature +header behavior of the OpenAI client returned by AIProjectClient.get_openai_client(). No network calls are made. """ +from unittest.mock import patch + import pytest from azure.core.credentials import AccessToken from azure.ai.projects import AIProjectClient +from azure.ai.projects.models._patch import _FOUNDRY_FEATURES_HEADER_NAME + +from openai_test_helpers import ( + ENDPOINT, + API_VERSION, + SYNC_OPENAI_PATCH, + SYNC_TOKEN_PROVIDER_PATCH, + make_sync_client, + mock_openai, +) FAKE_ENDPOINT = "https://fake-account.services.ai.azure.com/api/projects/fake-project" AGENT_NAME = "fake-agent-name" @@ -59,3 +72,106 @@ def test_get_openai_client_with_agent_name_and_allow_preview(self): expected_base_url = FAKE_ENDPOINT.rstrip("/") + f"/agents/{AGENT_NAME}/endpoint/protocols/openai" assert str(openai_client.base_url).rstrip("/") == expected_base_url + + def test_trailing_slash_on_endpoint_is_stripped(self): + """Trailing slash on endpoint must not produce a double slash in the base URL.""" + client = make_sync_client() + client._config.endpoint = ENDPOINT + "/" + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + for c in mock_cls.call_args_list: + host = c.kwargs["base_url"].replace("https://", "") + assert "//" not in host + + +# =========================================================================== +# default_query / api-version injection branches +# =========================================================================== + + +class TestDefaultQueryBranches: + def test_no_agent_no_api_version_injected(self): + """Branch: no agent_name -> api-version is NOT injected into default_query.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + for c in mock_cls.call_args_list: + assert "api-version" not in c.kwargs.get("default_query", {}) + + def test_agent_injects_api_version(self): + """Branch: agent_name + no caller api-version -> inject SDK api_version.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(agent_name="my-agent") + for c in mock_cls.call_args_list: + assert c.kwargs["default_query"]["api-version"] == API_VERSION + + def test_agent_does_not_override_caller_api_version(self): + """Branch: agent_name + caller-provided api-version -> keep caller value.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(agent_name="my-agent", default_query={"api-version": "caller-v"}) + for c in mock_cls.call_args_list: + assert c.kwargs["default_query"]["api-version"] == "caller-v" + + def test_caller_default_query_values_preserved(self): + """Caller-supplied default_query keys other than api-version are preserved.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(default_query={"foo": "bar"}) + for c in mock_cls.call_args_list: + assert c.kwargs["default_query"]["foo"] == "bar" + + +# =========================================================================== +# Foundry feature header injection branches +# =========================================================================== + + +class TestFoundryFeatureHeaderBranches: + def test_no_agent_no_feature_header_injected(self): + """Branch: no agent_name -> Foundry feature header is NOT injected.""" + + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + real_call = mock_cls.call_args_list[-1] + assert _FOUNDRY_FEATURES_HEADER_NAME not in real_call.kwargs.get("default_headers", {}) + + def test_agent_injects_foundry_feature_header(self): + """Branch: agent_name + header not present -> inject the Foundry feature header.""" + + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(agent_name="my-agent") + real_call = mock_cls.call_args_list[-1] + assert _FOUNDRY_FEATURES_HEADER_NAME in real_call.kwargs.get("default_headers", {}) + + def test_agent_does_not_override_existing_feature_header(self): + """Branch: agent_name + header already in caller headers -> keep caller value.""" + + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client( + agent_name="my-agent", + default_headers={_FOUNDRY_FEATURES_HEADER_NAME: "caller-value"}, + ) + real_call = mock_cls.call_args_list[-1] + assert real_call.kwargs["default_headers"][_FOUNDRY_FEATURES_HEADER_NAME] == "caller-value" + + def test_caller_headers_other_keys_preserved(self): + """Caller-supplied non-feature headers are passed through to the OpenAI client.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(default_headers={"X-My-Header": "hello"}) + real_call = mock_cls.call_args_list[-1] + assert real_call.kwargs["default_headers"]["X-My-Header"] == "hello" diff --git a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint_async.py b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint_async.py index f489a4f982b6..8335531787af 100644 --- a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint_async.py +++ b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_endpoint_async.py @@ -4,14 +4,27 @@ # Licensed under the MIT License. # ------------------------------------ """ -Unit tests for verifying the base_url of the AsyncOpenAI client returned by AIProjectClient.get_openai_client(). +Unit tests for verifying the base_url, default_query (api-version) and Foundry feature +header behavior of the AsyncOpenAI client returned by AIProjectClient.get_openai_client(). No network calls are made. """ -import pytest from typing import Any +from unittest.mock import patch + +import pytest from azure.core.credentials_async import AsyncTokenCredential from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models._patch import _FOUNDRY_FEATURES_HEADER_NAME + +from openai_test_helpers import ( + ENDPOINT, + API_VERSION, + ASYNC_OPENAI_PATCH, + ASYNC_TOKEN_PROVIDER_PATCH, + make_async_client, + mock_openai, +) FAKE_ENDPOINT = "https://fake-account.services.ai.azure.com/api/projects/fake-project" AGENT_NAME = "fake-agent-name" @@ -68,3 +81,95 @@ async def test_get_openai_client_with_agent_name_and_allow_preview_async(self): expected_base_url = FAKE_ENDPOINT.rstrip("/") + f"/agents/{AGENT_NAME}/endpoint/protocols/openai" assert str(openai_client.base_url).rstrip("/") == expected_base_url + + @pytest.mark.asyncio + async def test_trailing_slash_on_endpoint_is_stripped_async(self): + """Trailing slash on endpoint must not produce a double slash in the base URL.""" + client = make_async_client() + client._config.endpoint = ENDPOINT + "/" + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + for c in mock_cls.call_args_list: + host = c.kwargs["base_url"].replace("https://", "") + assert "//" not in host + + +# =========================================================================== +# default_query / api-version injection branches (async) +# =========================================================================== + + +class TestDefaultQueryBranchesAsync: + @pytest.mark.asyncio + async def test_no_agent_no_api_version_injected(self): + """Branch: no agent_name -> api-version is NOT injected into default_query.""" + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + for c in mock_cls.call_args_list: + assert "api-version" not in c.kwargs.get("default_query", {}) + + @pytest.mark.asyncio + async def test_agent_injects_api_version(self): + """Branch: agent_name + no caller api-version -> inject SDK api_version.""" + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(agent_name="my-agent") + for c in mock_cls.call_args_list: + assert c.kwargs["default_query"]["api-version"] == API_VERSION + + @pytest.mark.asyncio + async def test_agent_does_not_override_caller_api_version(self): + """Branch: agent_name + caller-provided api-version -> keep caller value.""" + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(agent_name="my-agent", default_query={"api-version": "caller-v"}) + for c in mock_cls.call_args_list: + assert c.kwargs["default_query"]["api-version"] == "caller-v" + + +# =========================================================================== +# Foundry feature header injection branches (async) +# =========================================================================== + + +class TestFoundryFeatureHeaderBranchesAsync: + @pytest.mark.asyncio + async def test_no_agent_no_feature_header_injected(self): + """Branch: no agent_name -> Foundry feature header is NOT injected.""" + + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + real_call = mock_cls.call_args_list[-1] + assert _FOUNDRY_FEATURES_HEADER_NAME not in real_call.kwargs.get("default_headers", {}) + + @pytest.mark.asyncio + async def test_agent_injects_foundry_feature_header(self): + """Branch: agent_name + header not present -> inject the Foundry feature header.""" + + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client(agent_name="my-agent") + real_call = mock_cls.call_args_list[-1] + assert _FOUNDRY_FEATURES_HEADER_NAME in real_call.kwargs.get("default_headers", {}) + + @pytest.mark.asyncio + async def test_agent_does_not_override_existing_feature_header(self): + """Branch: agent_name + header already in caller headers -> keep caller value.""" + + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client( + agent_name="my-agent", + default_headers={_FOUNDRY_FEATURES_HEADER_NAME: "caller-value"}, + ) + real_call = mock_cls.call_args_list[-1] + assert real_call.kwargs["default_headers"][_FOUNDRY_FEATURES_HEADER_NAME] == "caller-value" diff --git a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides.py b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides.py index 782c5024f43a..e0895ae552ca 100644 --- a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides.py +++ b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides.py @@ -4,17 +4,27 @@ # Licensed under the MIT License. # ------------------------------------ """ -Tests to verify that a custom http_client can be passed to get_openai_client() -and that the returned OpenAI client uses it instead of the default one. +Tests covering caller-side overrides (http_client, api_key, base_url, default_headers) +and the user-agent / token-provider / logging-transport branches of +AIProjectClient.get_openai_client() (sync). """ import os from typing import Any +from unittest.mock import patch + import pytest import httpx from azure.core.credentials import TokenCredential from azure.ai.projects import AIProjectClient +from openai_test_helpers import ( + SYNC_OPENAI_PATCH, + SYNC_TOKEN_PROVIDER_PATCH, + make_sync_client, + mock_openai, +) + class DummyTokenCredential(TokenCredential): """A dummy credential that returns None for testing purposes.""" @@ -134,3 +144,60 @@ def test_api_key_and_base_url_overrides(self): assert ( str(openai_client.base_url) == custom_base_url + "/" ), f"Expected base_url '{custom_base_url}/', got '{openai_client.base_url}'" + + +# =========================================================================== +# api_key resolution branches +# =========================================================================== + + +class TestApiKeyBranches: + def test_token_provider_used_when_no_api_key(self): + """Branch: no 'api_key' kwarg -> get_bearer_token_provider() is invoked.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="provider") as mock_tp: + client.get_openai_client() + mock_tp.assert_called_once_with(client._config.credential, "https://ai.azure.com/.default") + for c in mock_cls.call_args_list: + assert c.kwargs["api_key"] == "provider" + + def test_caller_api_key_skips_token_provider(self): + """Branch: 'api_key' in kwargs -> token provider is NOT called.""" + client = make_sync_client() + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH) as mock_tp: + client.get_openai_client(api_key="my-secret-key") + mock_tp.assert_not_called() + for c in mock_cls.call_args_list: + assert c.kwargs["api_key"] == "my-secret-key" + + +# =========================================================================== +# http_client resolution branches +# =========================================================================== + + +class TestHttpClientBranches: + def test_http_client_is_none_by_default(self): + """Branch: no override + console logging off -> http_client is None.""" + client = make_sync_client(console_logging=False) + mock_cls, _ = mock_openai() + with patch(SYNC_OPENAI_PATCH, mock_cls), patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + for c in mock_cls.call_args_list: + assert c.kwargs["http_client"] is None + + def test_console_logging_creates_logging_transport(self): + """Branch: no override + _console_logging_enabled=True -> httpx.Client with logging transport.""" + client = make_sync_client(console_logging=True) + mock_cls, _ = mock_openai() + with ( + patch(SYNC_OPENAI_PATCH, mock_cls), + patch(SYNC_TOKEN_PROVIDER_PATCH, return_value="tok"), + patch("azure.ai.projects._patch.httpx") as mock_httpx, + patch("azure.ai.projects._patch._OpenAILoggingTransport"), + ): + mock_httpx.Client.return_value = object() + client.get_openai_client() + mock_httpx.Client.assert_called_once() diff --git a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides_async.py b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides_async.py index de8c484fd9f6..220dc961d22a 100644 --- a/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides_async.py +++ b/sdk/ai/azure-ai-projects/tests/responses/test_openai_client_overrides_async.py @@ -4,17 +4,27 @@ # Licensed under the MIT License. # ------------------------------------ """ -Tests to verify that a custom http_client can be passed to get_openai_client() -and that the returned AsyncOpenAI client uses it instead of the default one. +Tests covering caller-side overrides (http_client, api_key, base_url, default_headers) +and the user-agent / token-provider / logging-transport branches of +AIProjectClient.get_openai_client() (async). """ import os from typing import Any +from unittest.mock import patch + import pytest import httpx from azure.core.credentials_async import AsyncTokenCredential from azure.ai.projects.aio import AIProjectClient +from openai_test_helpers import ( + ASYNC_OPENAI_PATCH, + ASYNC_TOKEN_PROVIDER_PATCH, + make_async_client, + mock_openai, +) + class DummyAsyncTokenCredential(AsyncTokenCredential): """A dummy async credential that returns None for testing purposes.""" @@ -138,3 +148,67 @@ async def test_api_key_and_base_url_overrides_async(self): assert ( str(openai_client.base_url) == custom_base_url + "/" ), f"Expected base_url '{custom_base_url}/', got '{openai_client.base_url}'" + + +# =========================================================================== +# api_key resolution branches (async) +# =========================================================================== + + +class TestApiKeyBranchesAsync: + @pytest.mark.asyncio + async def test_token_provider_used_when_no_api_key(self): + """Branch: no 'api_key' kwarg -> get_bearer_token_provider() is invoked.""" + client = make_async_client() + mock_cls, _ = mock_openai() + with ( + patch(ASYNC_OPENAI_PATCH, mock_cls), + patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="async-provider") as mock_tp, + ): + client.get_openai_client() + mock_tp.assert_called_once_with(client._config.credential, "https://ai.azure.com/.default") + for c in mock_cls.call_args_list: + assert c.kwargs["api_key"] == "async-provider" + + @pytest.mark.asyncio + async def test_caller_api_key_skips_token_provider(self): + """Branch: 'api_key' in kwargs -> token provider is NOT called.""" + client = make_async_client() + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH) as mock_tp: + client.get_openai_client(api_key="async-secret") + mock_tp.assert_not_called() + for c in mock_cls.call_args_list: + assert c.kwargs["api_key"] == "async-secret" + + +# =========================================================================== +# http_client resolution branches (async) +# =========================================================================== + + +class TestHttpClientBranchesAsync: + @pytest.mark.asyncio + async def test_http_client_is_none_by_default(self): + """Branch: no override + console logging off -> http_client is None.""" + client = make_async_client(console_logging=False) + mock_cls, _ = mock_openai() + with patch(ASYNC_OPENAI_PATCH, mock_cls), patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"): + client.get_openai_client() + for c in mock_cls.call_args_list: + assert c.kwargs["http_client"] is None + + @pytest.mark.asyncio + async def test_console_logging_creates_async_logging_transport(self): + """Branch: no override + _console_logging_enabled=True -> httpx.AsyncClient with logging transport.""" + client = make_async_client(console_logging=True) + mock_cls, _ = mock_openai() + with ( + patch(ASYNC_OPENAI_PATCH, mock_cls), + patch(ASYNC_TOKEN_PROVIDER_PATCH, return_value="tok"), + patch("azure.ai.projects.aio._patch.httpx") as mock_httpx, + patch("azure.ai.projects.aio._patch._OpenAILoggingTransport"), + ): + mock_httpx.AsyncClient.return_value = object() + client.get_openai_client() + mock_httpx.AsyncClient.assert_called_once() diff --git a/sdk/ai/azure-ai-projects/tests/samples/sample_executor.py b/sdk/ai/azure-ai-projects/tests/samples/sample_executor.py index 4c7d990c2975..9fc9adfa3698 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/sample_executor.py +++ b/sdk/ai/azure-ai-projects/tests/samples/sample_executor.py @@ -242,9 +242,15 @@ def _capture_debug_logs(self): """Capture logger DEBUG output into the same array used for print capture.""" bearer_token_pattern = re.compile(r"(?i)(Bearer\s+)([^\s\"',;]+)") + # Matches raw JWT-like tokens assigned to an "authorization" JSON field + # (e.g., when a sample passes `authorization=token` to MCPTool, the request + # body is logged as `"authorization": "eyJ..."` without a "Bearer " prefix). + json_authorization_pattern = re.compile(r"(?i)(\"authorization\"\s*:\s*\")([^\"]+)(\")") def _sanitize_log_message(message: str) -> str: - return bearer_token_pattern.sub(r"\1", message) + message = bearer_token_pattern.sub(r"\1", message) + message = json_authorization_pattern.sub(r"\1\3", message) + return message class _PrintCaptureLogHandler(logging.Handler): def __init__(self, sink: list[str]): @@ -1044,13 +1050,11 @@ def _resolve_additional_env_vars( resolved: dict[str, str] = {} if _is_live_mode(): - for env_key, _ in playback_values.items(): + for env_key, playback_value in playback_values.items(): live_value = os.environ.get(env_key) if not live_value: - raise ValueError( - f"Missing required environment variable '{env_key}' for live recording of sample '{sample_filename}'. " - "Either set it in your environment/.env file or run in playback mode." - ) + resolved[env_key] = playback_value + continue resolved[env_key] = live_value else: resolved.update(playback_values) 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 4ae4f4010925..598e9e3e564e 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, @@ -85,6 +85,7 @@ def test_memory_samples(self, sample_path: str, **kwargs) -> None: get_sample_paths( "agents", samples_to_skip=[ + "sample_external_agents_crud.py", # Skipped until recordings are available. "sample_workflow_multi_agent.py", # No issue to run. Just postpone recording. "sample_workflow_multi_agent_with_mcp_approval.py", # No issue to run. Just postpone recording. ], @@ -152,11 +153,63 @@ def test_deployments_samples(self, sample_path: str, **kwargs) -> None: @pytest.mark.parametrize( "sample_path", get_sample_paths( - "datasets", - samples_to_skip=[], + "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_create_and_poll.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( + # [ + # AdditionalSampleTestDetail( + # test_id="sample_dataset_generation_job_simpleqna_with_prompt_source", + # sample_filename="sample_dataset_generation_job_simpleqna_with_prompt_source.py", + # env_vars={ + # "POLL_INTERVAL_SECONDS": "60", + # }, + # ), + # ] + # ) + @pytest.mark.parametrize( + "sample_path", + get_sample_paths( + "datasets", + samples_to_skip=[ + "sample_dataset_generation_job_simpleqna_with_prompt_source.py", # PR #47067: recording not yet available + "sample_dataset_generation_job_traces_for_finetuning.py", # PR #47067: recording not yet available + "sample_dataset_generation_job_simpleqna_for_finetuning.py", # PR #47067: recording not yet available + "sample_dataset_generation_job_traces_for_evaluation.py", # PR #47067: recording not yet available + "sample_dataset_generation_job_simpleqna_with_agent_source.py", # PR #47067: recording not yet available + "sample_dataset_generation_job_simpleqna_with_file_source.py", # PR #47067: recording not yet available + ], + ), + ) @SamplePathPasser() @recorded_by_proxy(RecordedTransport.AZURE_CORE, RecordedTransport.HTTPX) def test_datasets_samples(self, sample_path: str, **kwargs) -> None: @@ -181,6 +234,18 @@ def test_chat_completions_samples(self, sample_path: str, **kwargs) -> None: executor.execute() executor.validate_print_calls_by_llm() + @servicePreparer() + @additionalSampleTests( + [ + AdditionalSampleTestDetail( + test_id="sample_create_hosted_agent_from_remote_build", + sample_filename="sample_create_hosted_agent_from_code.py", + env_vars={ + "FOUNDRY_HOSTED_AGENT_REMOTE_BUILD": "true", + }, + ), + ] + ) @pytest.mark.parametrize( "sample_path", get_sample_paths( @@ -188,10 +253,11 @@ def test_chat_completions_samples(self, sample_path: str, **kwargs) -> None: samples_to_skip=[], ), ) - @servicePreparer() @SamplePathPasser() @recorded_by_proxy(RecordedTransport.AZURE_CORE, RecordedTransport.HTTPX) def test_hosted_agents_samples(self, sample_path: str, **kwargs) -> None: + if os.path.basename(sample_path).startswith("sample_create_hosted_agent") and not self.is_live: + pytest.skip("sample_create_hosted_agent.py is skipped in replay mode due to RBAC complications.") env_vars = get_sample_env_vars(kwargs) executor = SyncSampleExecutor(self, sample_path, env_vars=env_vars, **kwargs) executor.execute() 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 1c742537c5fc..e3b76dacf469 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 @@ -3,13 +3,15 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -import pytest +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, SamplePathPasser, + additionalSampleTests, get_async_sample_paths, ) from test_samples_helpers import get_sample_env_vars @@ -69,7 +71,10 @@ async def test_memory_samples(self, sample_path: str, **kwargs) -> None: "sample_path", get_async_sample_paths( "agents", - samples_to_skip=["sample_workflow_multi_agent_async.py"], + samples_to_skip=[ + "sample_external_agents_crud_async.py", # Skipped until recordings are available. + "sample_workflow_multi_agent_async.py", + ], ), ) @servicePreparer() @@ -133,6 +138,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( @@ -170,6 +202,18 @@ async def test_chat_completions_samples(self, sample_path: str, **kwargs) -> Non await executor.execute_async() await executor.validate_print_calls_by_llm_async() + @servicePreparer() + @additionalSampleTests( + [ + AdditionalSampleTestDetail( + test_id="sample_create_hosted_agent_from_remote_build_async", + sample_filename="sample_create_hosted_agent_from_code_async.py", + env_vars={ + "FOUNDRY_HOSTED_AGENT_REMOTE_BUILD": "true", + }, + ), + ] + ) @pytest.mark.parametrize( "sample_path", get_async_sample_paths( @@ -177,10 +221,11 @@ async def test_chat_completions_samples(self, sample_path: str, **kwargs) -> Non samples_to_skip=[], ), ) - @servicePreparer() @SamplePathPasser() @recorded_by_proxy_async(RecordedTransport.AZURE_CORE, RecordedTransport.HTTPX) async def test_hosted_agents_samples(self, sample_path: str, **kwargs) -> None: + if os.path.basename(sample_path).startswith("sample_create_hosted_agent") and not self.is_live: + pytest.skip("sample_create_hosted_agent.py is skipped in replay mode due to RBAC complications.") env_vars = get_sample_env_vars(kwargs) executor = AsyncSampleExecutor(self, sample_path, env_vars=env_vars, **kwargs) await executor.execute_async() diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_samples_evaluations.py b/sdk/ai/azure-ai-projects/tests/samples/test_samples_evaluations.py index 2618d0320a05..0d955caf78d6 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/test_samples_evaluations.py +++ b/sdk/ai/azure-ai-projects/tests/samples/test_samples_evaluations.py @@ -78,6 +78,7 @@ class TestSamplesEvaluations(AzureRecordedTestCase): Main evaluation samples (13): - sample_agent_evaluation.py - sample_model_evaluation.py + - sample_model_evaluation_instant_model.py - sample_agent_response_evaluation.py - sample_agent_response_evaluation_with_function_tool.py - sample_evaluations_builtin_with_inline_data.py @@ -152,6 +153,15 @@ class TestSamplesEvaluations(AzureRecordedTestCase): "sample_synthetic_data_agent_evaluation.py", # Synthetic data gen is long-running preview feature "sample_synthetic_data_model_evaluation.py", # Synthetic data gen is long-running preview feature "sample_eval_catalog_prompt_based_evaluators.py", # For some reason fails with 500 (Internal server error) + "sample_multiturn_conversation_evaluation.py", # PR #47034: new multi-turn sample, recording not yet available + "sample_multiturn_conversation_simulation.py", # PR #47034: new multi-turn sample, recording not yet available + "sample_multiturn_trace_evaluation_agent_filter.py", # PR #47034: new multi-turn sample, recording not yet available + "sample_multiturn_trace_evaluation_by_id.py", # PR #47034: new multi-turn sample, recording not yet available + "sample_rubric_evaluator_generation_all_sources.py", # PR #47057: recording not yet available + "sample_rubric_evaluator_generation_lifecycle.py", # PR #47057: recording not yet available + "sample_rubric_evaluator_generation_basic.py", # PR #47057: recording not yet available + "sample_rubric_evaluator_manual.py", # PR #47057: recording not yet available + "sample_rubric_evaluator_generation_iterate.py", # PR #47057: recording not yet available ], ), ) diff --git a/sdk/ai/azure-ai-projects/tests/test_base.py b/sdk/ai/azure-ai-projects/tests/test_base.py index 0979f5a177b6..5b69b45ce21a 100644 --- a/sdk/ai/azure-ai-projects/tests/test_base.py +++ b/sdk/ai/azure-ai-projects/tests/test_base.py @@ -54,6 +54,7 @@ mcp_project_connection_id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sanitized-resource-group/providers/Microsoft.CognitiveServices/accounts/sanitized-account/projects/sanitized-project/connections/sanitized-mcp-connection", browser_automation_project_connection_id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sanitized-resource-group/providers/Microsoft.CognitiveServices/accounts/sanitized-account/projects/sanitized-project/connections/sanitized-browser-automation-connection", sharepoint_project_connection_id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sanitized-resource-group/providers/Microsoft.CognitiveServices/accounts/sanitized-account/projects/sanitized-project/connections/sanitized-sharepoint-connection", + fabric_iq_project_connection_id="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/sanitized-resource-group/providers/Microsoft.CognitiveServices/accounts/sanitized-account/projects/sanitized-project/connections/sanitized-fabric-iq-connection", bing_custom_search_instance_name="sanitized-bing-custom-search-instance", completed_oai_model_sft_fine_tuning_job_id="sanitized-ftjob-id", completed_oai_model_rft_fine_tuning_job_id="sanitized-ftjob-id", @@ -68,9 +69,11 @@ fabric_user_input="List all customers!", a2a_user_input="What can the secondary agent do?", bing_custom_user_input="Tell me more about foundry agent service", + fabric_iq_user_input="Tell me weather history in London, Ohio", memory_store_chat_model_deployment_name="sanitized-model-deployment-name", memory_store_embedding_model_deployment_name="text-embedding-ada-002", foundry_agent_container_image="sanitizedregistry.azurecr.io/sanitized/sessions-agent:latest", + foundry_hosted_agent_name="sanitized-hosted-agent-name", ) fineTuningServicePreparer = functools.partial( @@ -84,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" @@ -203,6 +216,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 diff --git a/sdk/ai/azure-ai-projects/tsp-location-omitted.yaml b/sdk/ai/azure-ai-projects/tsp-location.yaml similarity index 69% rename from sdk/ai/azure-ai-projects/tsp-location-omitted.yaml rename to sdk/ai/azure-ai-projects/tsp-location.yaml index 70b8d1cf4350..1d28b6a52b56 100644 --- a/sdk/ai/azure-ai-projects/tsp-location-omitted.yaml +++ b/sdk/ai/azure-ai-projects/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/ai-foundry/data-plane/Foundry -commit: 9f045138c73bf7aa13ee59b805cd9143dbb77835 +commit: 53fbe53ff36e1d41dc9d12dbfd949182b07a88bf repo: Azure/azure-rest-api-specs additionalDirectories: