diff --git a/.vscode/cspell.json b/.vscode/cspell.json index 40292925988b..9c2fae2ff062 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -593,6 +593,22 @@ "runid" ] }, + { + "filename": "sdk/ai/azure-ai-projects/**", + "words": [ + "brise", + "flitz", + "harema", + "juni", + "nira", + "noeul", + "nuri", + "orgid", + "shida", + "unmute", + "unmuted" + ] + }, { "filename": [ "sdk/ai/azure-ai-projects/tests.yml", diff --git a/eng/emitter-package-lock.json b/eng/emitter-package-lock.json index 6dea4b09bc34..1212893b6534 100644 --- a/eng/emitter-package-lock.json +++ b/eng/emitter-package-lock.json @@ -9,7 +9,7 @@ "@azure-tools/typespec-python": "0.63.10" }, "devDependencies": { - "@azure-tools/openai-typespec": "1.28.0", + "@azure-tools/openai-typespec": "1.34.1", "@azure-tools/typespec-autorest": "~0.73.0", "@azure-tools/typespec-azure-core": "~0.73.0", "@azure-tools/typespec-azure-portal-core": "~0.73.0", @@ -31,9 +31,9 @@ } }, "node_modules/@azure-tools/openai-typespec": { - "version": "1.28.0", - "resolved": "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-js/npm/registry/@azure-tools/openai-typespec/-/openai-typespec-1.28.0.tgz", - "integrity": "sha1-rXCoTFopEeA3qKL8/P3Uim0ZuuA=", + "version": "1.34.1", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@azure-tools/openai-typespec/-/openai-typespec-1.34.1.tgz", + "integrity": "sha512-lEkeHLHbHZKDdyvntS4Q51ghFKrn3aF2wDHUFoHhWgBgOqwtE3mFEsnSCfe6Kx1hIcNixvYPX3Rxclc6mBg6oA==", "dev": true, "license": "MIT", "peerDependencies": { diff --git a/eng/emitter-package.json b/eng/emitter-package.json index 79c0abbe49bf..72c836080e38 100644 --- a/eng/emitter-package.json +++ b/eng/emitter-package.json @@ -22,6 +22,6 @@ "@azure-tools/typespec-client-generator-core": "~0.73.0", "@azure-tools/typespec-azure-portal-core": "~0.73.0", "@azure-tools/typespec-liftr-base": "0.13.0", - "@azure-tools/openai-typespec": "1.28.0" + "@azure-tools/openai-typespec": "1.34.1" } } diff --git a/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/SKILL.md b/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/SKILL.md index 8e2b7f3ca6c1..969137dcd298 100644 --- a/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/SKILL.md +++ b/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/SKILL.md @@ -1,123 +1,19 @@ --- name: azure-ai-projects-model-reference-graph -description: 'Generate and analyze the azure-ai-projects model reference graph from models/_models.py through model references, inheritance, runtime ownership, and public operation methods. WHEN: find which operations use a model; trace model dependencies; generate model-reference-graph.json; generate model-reference-trees.txt; investigate unused or orphaned generated models; assess whether a TypeSpec model may be removable. DO NOT USE FOR: deleting generated models automatically; packages other than azure-ai-projects. INVOKES: GenerateModelReferenceGraph.ps1, Python JSON validation, git diff checks.' -argument-hint: 'Optionally provide a model name to inspect after generating the graph' +description: 'Generate the azure-ai-projects model reference graph, trace operation dependencies, and identify unreferenced models. Writes validated, timestamped JSON and TXT reports to the user temp folder. Use for model-reference graphs, unused models, or TypeSpec removal investigation; not automatic model deletion or other packages.' +argument-hint: 'Optional model name' --- # Generate the azure-ai-projects model reference graph -Run this workflow from `sdk\ai\azure-ai-projects`. - -## 1. Check prerequisites - -Confirm the package root and required files: - -```powershell -git rev-parse --show-prefix -Test-Path .\.github\skills\azure-ai-projects-model-reference-graph\scripts\GenerateModelReferenceGraph.ps1 -Test-Path .\azure\ai\projects\models\_models.py -``` - -The Git prefix must be `sdk/ai/azure-ai-projects/`. Stop and report the missing prerequisite if either file does not exist. - -Prefer the active virtual environment's Python. Use `.\.venv\Scripts\python.exe` when it exists; otherwise use `python`. - -## 2. Generate the graph - -```powershell -.\.github\skills\azure-ai-projects-model-reference-graph\scripts\GenerateModelReferenceGraph.ps1 ` - -PythonExecutable .\.venv\Scripts\python.exe -``` - -The script produces: - -- `model-reference-graph.json`: structured data keyed by every class in `_models.py`. -- `model-reference-trees.txt`: readable reverse-reference trees rooted at every model. - -Do not edit generated artifacts manually. Rerun the script after SDK emission or model changes. - -## 3. Interpret the graph - -For each model, follow children toward public operations: - -```text -ChildModel - `- BaseModel [base class] - `- RequestOrResponseModel - `- SomeOperations.method [operation] -``` - -Edge and marker meanings: - -- An unmarked model child directly references its parent through a field, annotation, decorator, or other model declaration. -- `[base class]` traverses from a derived model to its base type. -- `[derived class]` traverses from a base model to a derived type. -- `[operation]` is a public sync/async-deduplicated operation method. -- `[cycle]` stops a circular model relationship. -- `[already expanded]` identifies a shared branch already rendered under the same root. - -The JSON entry additionally contains direct and indirect model referrers, bases, derived models, operation references, paths, public-export status, and non-operation references. - -Some runtime ownership is not expressible through Python method annotations. The generator maintains an explicit, reviewed ownership table for WebSocket protocol messages, custom polling results, and flattened request bodies. Do not add a mapping based only on similar names. Verify the owning endpoint, handwritten patch, protocol documentation, or generated method implementation first. - -## 4. Inspect a requested model - -When the user supplies a model name, report: - -1. Its base and derived models. -2. Models that reference it directly and indirectly. -3. Every public operation it reaches, distinguishing direct references from inherited or transitive paths. -4. At least one representative path from the operation to the requested model. -5. Non-operation references from patches, tests, or samples. - -Use PowerShell for a focused JSON lookup: - -```powershell -$graph = Get-Content .\model-reference-graph.json -Raw | ConvertFrom-Json -AsHashtable -$graph.models[''] | ConvertTo-Json -Depth 10 -``` - -## 5. Validate generated artifacts - -Run all checks after generation: - -```powershell -$tokens = $null -$errors = $null -[System.Management.Automation.Language.Parser]::ParseFile( - (Resolve-Path '.\.github\skills\azure-ai-projects-model-reference-graph\scripts\GenerateModelReferenceGraph.ps1'), - [ref]$tokens, - [ref]$errors -) | Out-Null -if ($errors.Count) { throw ($errors.Message -join [Environment]::NewLine) } - -python -m json.tool .\model-reference-graph.json > $null -git diff --check -- .\.github\skills\azure-ai-projects-model-reference-graph\scripts\GenerateModelReferenceGraph.ps1 .\model-reference-graph.json .\model-reference-trees.txt -``` - -Also verify the summary against the structured graph: +Run from `sdk\ai\azure-ai-projects`: ```powershell -$graph = Get-Content .\model-reference-graph.json -Raw | ConvertFrom-Json -AsHashtable -$withoutOperations = @($graph.models.GetEnumerator() | Where-Object { $_.Value.pathsToOperations.Count -eq 0 }) -if ($withoutOperations.Count -ne $graph.metadata.modelsWithoutOperationPaths) { - throw 'The tree summary does not match the structured graph.' -} +.\.github\skills\azure-ai-projects-model-reference-graph\scripts\GenerateModelReferenceGraph.ps1 ``` -## 6. Apply removal safeguards - -Operation reachability is not proof that a model is safe or unsafe to remove. Before proposing removal, verify all of the following: - -- Public export status in `models/__init__.py`. -- References from `_patch.py`, `_unions.py`, samples, and tests. -- Base classes, derived classes, and discriminator registration. -- Runtime protocol roles such as WebSocket events and LRO polling bodies. -- The corresponding TypeSpec declaration and all TypeSpec references. -- API review impact after regenerating the SDK. - -Never delete generated classes directly from `_models.py`. Remove or correct the TypeSpec source, regenerate the SDK, rerun this skill, and run package validation. - -## 7. Report results +Add `-ModelName ''` when inspecting a specific model. -Report the model count, models with and without operation paths, requested model paths, explicit runtime ownership mappings used, and validation results. Clearly label static-analysis limitations and any model requiring TypeSpec or runtime review. \ No newline at end of file +The script handles prerequisites, Python selection, report generation, validation, +and summaries. Report its results and both absolute output paths. +Unreferenced models require TypeSpec/runtime/API review, not automatic deletion. \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/scripts/GenerateModelReferenceGraph.ps1 b/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/scripts/GenerateModelReferenceGraph.ps1 index b85eb2427c6c..706904ae0efc 100644 --- a/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/scripts/GenerateModelReferenceGraph.ps1 +++ b/sdk/ai/azure-ai-projects/.github/skills/azure-ai-projects-model-reference-graph/scripts/GenerateModelReferenceGraph.ps1 @@ -1,26 +1,51 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +<# +.SYNOPSIS +Generates and validates model-reference reports in the user's temp directory. +.DESCRIPTION +Uses the package virtual environment when available, otherwise Python on PATH. +JSON and TXT filenames share a UTC timestamp. Explicit output paths are supported. +Prints counts, unreferenced models, runtime owners, and absolute report locations; +returns GraphPath and TreePath. Use -ModelName for a model's complete reference entry. +Unreferenced excludes definitions and public exports, but includes union aliases, +runtime code, samples, tests, and inheritance. Operation reachability alone does not +prove safe removal: review TypeSpec, runtime consumers, discriminators, public exports, +and regenerated API impact before changing TypeSpec and regenerating the SDK. +Never delete generated classes directly. +#> [CmdletBinding()] param( - [string]$PythonExecutable = "python", + [string]$PythonExecutable, [string]$ModelsPath, [string]$OutputPath, - [string]$TreeOutputPath + [string]$TreeOutputPath, + [string]$ModelName ) $ErrorActionPreference = "Stop" $packageRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..\..")).Path +if (-not $PythonExecutable) { + $packagePython = Join-Path $packageRoot ".venv\Scripts\python.exe" + $PythonExecutable = if (Test-Path -LiteralPath $packagePython -PathType Leaf) { $packagePython } else { "python" } +} +Get-Command -Name $PythonExecutable -CommandType Application -ErrorAction Stop | Out-Null +$tempDirectory = [System.IO.Path]::GetTempPath() +$timestamp = [DateTime]::UtcNow.ToString("yyyyMMdd-HHmmss'Z'", [Globalization.CultureInfo]::InvariantCulture) if (-not $ModelsPath) { $ModelsPath = Join-Path $packageRoot "azure\ai\projects\models\_models.py" } +if (-not (Test-Path -LiteralPath $ModelsPath -PathType Leaf)) { + throw "Required models file does not exist: $ModelsPath" +} if (-not $OutputPath) { - $OutputPath = Join-Path $packageRoot "model-reference-graph.json" + $OutputPath = Join-Path $tempDirectory "model-reference-graph-$timestamp.json" } if (-not $TreeOutputPath) { - $TreeOutputPath = Join-Path $packageRoot "model-reference-trees.txt" + $TreeOutputPath = Join-Path $tempDirectory "model-reference-trees-$timestamp.txt" } -$temporaryScript = Join-Path ([System.IO.Path]::GetTempPath()) ("generate-model-reference-graph-{0}.py" -f [guid]::NewGuid()) +$temporaryScript = Join-Path $tempDirectory ("generate-model-reference-graph-{0}.py" -f [guid]::NewGuid()) $pythonScript = @' from __future__ import annotations @@ -38,6 +63,9 @@ package_root = Path(sys.argv[1]).resolve() models_path = Path(sys.argv[2]).resolve() output_path = Path(sys.argv[3]).resolve() tree_output_path = Path(sys.argv[4]).resolve() +requested_model = sys.argv[5] if len(sys.argv) > 5 else "" +if output_path == tree_output_path: + raise ValueError("JSON and TXT reports must use different output paths.") excluded_directories = { ".git", @@ -137,6 +165,8 @@ def assignment_nodes(tree: ast.Module) -> dict[str, ast.AST]: and isinstance(node.targets[0], ast.Name) ): assignments[node.targets[0].id] = node.value + elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name) and node.value is not None: + assignments[node.target.id] = node.value return assignments @@ -171,6 +201,8 @@ model_nodes = { if isinstance(node, ast.ClassDef) } known_models = set(model_nodes) +if requested_model and requested_model not in known_models: + raise ValueError(f"Unknown model: {requested_model}") unions_path = models_path.parent.parent / "_unions.py" union_nodes = assignment_nodes(parse_python(unions_path)) @@ -234,6 +266,11 @@ public_exports = find_public_exports(models_init_path, known_models) operation_references: dict[str, set[str]] = defaultdict(set) other_references: dict[str, set[str]] = defaultdict(set) +union_location = unions_path.relative_to(package_root).as_posix() +for union_name in sorted(known_unions): + for model_name in models_for_union(union_name): + other_references[model_name].add(f"{union_location}::{union_name}") + for path in python_files(package_root): resolved_path = path.resolve() if resolved_path in {models_path, models_init_path, unions_path}: @@ -252,17 +289,34 @@ for path in python_files(package_root): # These protocol/runtime models are owned by public operations but are intentionally # absent from their Python signatures: WebSocket messages flow over the upgraded # connection, and the memory update result is consumed by a custom polling method. +# Verify protocol/custom transport evidence before changing these mappings. runtime_operation_owners = { - "RealtimeClientEvent": "azure/ai/projects/operations/_operations.py::BetaVoiceAgentsRealtimeOperations._connect_voice_agent", - "RealtimeServerEvent": "azure/ai/projects/operations/_operations.py::BetaVoiceAgentsRealtimeOperations._connect_voice_agent", - "RealtimeServerEventError": "azure/ai/projects/operations/_operations.py::BetaVoiceAgentsRealtimeOperations._connect_voice_agent", - "VoiceAgentClientEventSessionUpdate": "azure/ai/projects/operations/_operations.py::BetaVoiceAgentsRealtimeOperations._connect_voice_agent", - "VoiceAgentSessionResponseConfig": "azure/ai/projects/operations/_operations.py::BetaVoiceAgentsRealtimeOperations._connect_voice_agent", - "VoiceAgentSessionUpdateConfig": "azure/ai/projects/operations/_operations.py::BetaVoiceAgentsRealtimeOperations._connect_voice_agent", + "RealtimeClientEvent": "azure/ai/projects/_realtime.py::BetaRealtime.connect", + "RealtimeServerEvent": "azure/ai/projects/_realtime.py::BetaRealtime.connect", + "RealtimeServerEventError": "azure/ai/projects/_realtime.py::BetaRealtime.connect", + "VoiceAgentClientEventSessionUpdate": "azure/ai/projects/_realtime.py::BetaRealtime.connect", + "VoiceAgentSessionResponseConfig": "azure/ai/projects/_realtime.py::BetaRealtime.connect", + "VoiceAgentSessionUpdateConfig": "azure/ai/projects/_realtime.py::BetaRealtime.connect", "MemoryStoreUpdateResult": "azure/ai/projects/operations/_patch_memories.py::BetaMemoryStoresOperations.begin_update_memories", "UpdateToolboxRequest": "azure/ai/projects/operations/_operations.py::ToolboxesOperations.update", } for model_name, operation in runtime_operation_owners.items(): + if model_name not in known_models: + raise ValueError(f"Runtime ownership mapping names a missing model: {model_name}") + owner_path, owner_scope = operation.split("::", maxsplit=1) + owner_class, owner_method = owner_scope.split(".", maxsplit=1) + owner_tree = parse_python(package_root / owner_path) + if owner_method.startswith("_") or not any( + isinstance(node, ast.ClassDef) + and node.name == owner_class + and any( + isinstance(member, (ast.FunctionDef, ast.AsyncFunctionDef)) + and member.name == owner_method + for member in node.body + ) + for node in owner_tree.body + ): + raise ValueError(f"Runtime ownership mapping names a missing or private method: {operation}") operation_references[model_name].add(operation) @@ -327,6 +381,11 @@ for name in sorted(known_models): models_without_operation_paths = [ name for name in sorted(known_models) if not graph[name]["pathsToOperations"] ] +unreferenced_models = [ + name + for name in sorted(known_models) + if not outward_models(name) and not operation_references[name] and not other_references[name] +] document = { "metadata": { @@ -335,6 +394,12 @@ document = { "modelsWithOperationPaths": models_with_operation_paths, "modelsWithoutOperationPaths": len(models_without_operation_paths), "modelsWithoutOperationPathNames": models_without_operation_paths, + "unreferencedModelCount": len(unreferenced_models), + "unreferencedModelNames": unreferenced_models, + "unreferencedModelCriteria": ( + "No model referrers, inheritance links, public operation references, or non-operation " + "references (including union aliases); definitions and public exports are excluded." + ), "explicitRuntimeOperationOwners": runtime_operation_owners, "pathSemantics": "Each path is operation -> referring models -> keyed model. One shortest model path is emitted for each reachable operation reference.", }, @@ -423,6 +488,15 @@ tree_lines = [ f"Models: {len(known_models)}", f"Models with a path to a public operation: {models_with_operation_paths}", f"Models with no path to a public operation: {len(models_without_operation_paths)}", + f"Unreferenced models: {len(unreferenced_models)}", + "", + "Unreferenced models (excluding definitions and public exports):", + *([f"- {name}" for name in unreferenced_models] if unreferenced_models else ["- None"]), + "", + "These have no model referrers, inheritance links, operation paths, or alias/patch/sample/test references.", + "Static analysis does not prove a publicly exported model is safe to remove.", + "Review public exports, aliases, runtime consumers, inheritance/discriminators, TypeSpec, and regenerated API impact.", + "Change TypeSpec and regenerate the SDK; never delete generated classes directly.", "", "Models with no path to a public operation:", *([f"- {name}" for name in models_without_operation_paths] if models_without_operation_paths else ["- None"]), @@ -437,21 +511,91 @@ for model_name in sorted(known_models): tree_output_path.parent.mkdir(parents=True, exist_ok=True) tree_output_path.write_text("\n".join(tree_lines), encoding="utf-8", newline="\n") -print( - f"Generated graph for {len(known_models)} models; " - f"{models_with_operation_paths} have a path to an operation." -) + + +def validate_reports(graph_path: Path, tree_path: Path) -> None: + saved = json.loads(graph_path.read_text(encoding="utf-8")) + saved_models = saved["models"] + without_operations = sorted( + name for name, entry in saved_models.items() if not entry["pathsToOperations"] + ) + unreferenced = sorted( + name + for name, entry in saved_models.items() + if not any( + entry[field] + for field in ( + "directModelReferrers", "baseModels", "derivedModels", + "pathsToOperations", "otherReferences", + ) + ) + ) + expected_metadata = { + "modelCount": len(saved_models), + "modelsWithOperationPaths": len(saved_models) - len(without_operations), + "modelsWithoutOperationPaths": len(without_operations), + "modelsWithoutOperationPathNames": without_operations, + "unreferencedModelCount": len(unreferenced), + "unreferencedModelNames": unreferenced, + } + for key, expected in expected_metadata.items(): + if saved["metadata"][key] != expected: + raise ValueError(f"JSON metadata does not match the graph: {key}") + + lines = tree_path.read_text(encoding="utf-8").splitlines() + for label, key in ( + ("Models", "modelCount"), + ("Models with a path to a public operation", "modelsWithOperationPaths"), + ("Models with no path to a public operation", "modelsWithoutOperationPaths"), + ("Unreferenced models", "unreferencedModelCount"), + ): + if f"{label}: {expected_metadata[key]}" not in lines: + raise ValueError(f"TXT summary does not match the graph: {label}") + for heading, names in ( + ("Unreferenced models (excluding definitions and public exports):", unreferenced), + ("Models with no path to a public operation:", without_operations), + ): + index = lines.index(heading) + 1 + listed_names = [] + while index < len(lines) and lines[index].startswith("- "): + listed_names.append(lines[index][2:]) + index += 1 + if listed_names != (names or ["None"]): + raise ValueError(f"TXT model list does not match the graph: {heading}") + + +validate_reports(output_path, tree_output_path) +print(f"Models: {len(known_models)}") +print(f"Models with operation paths: {models_with_operation_paths}") +print(f"Models without operation paths: {len(models_without_operation_paths)}") +print(f"Unreferenced models: {len(unreferenced_models)}") +for name in unreferenced_models or ["None"]: + print(f"- {name}") +print("Explicit runtime operation owners:") +for name, operation in runtime_operation_owners.items(): + print(f"- {name}: {operation}") +print("Validation passed: JSON/TXT counts and model lists match; runtime owners exist.") +print("Static analysis is not proof of safe removal; review TypeSpec/runtime/API impact.") print(f"Graph: {output_path}") print(f"Trees: {tree_output_path}") +if requested_model: + print(f"Model details: {requested_model}") + print(json.dumps(graph[requested_model], indent=2)) '@ try { [System.IO.File]::WriteAllText($temporaryScript, $pythonScript, [System.Text.UTF8Encoding]::new($false)) - & $PythonExecutable $temporaryScript $packageRoot $ModelsPath $OutputPath $TreeOutputPath + & $PythonExecutable $temporaryScript $packageRoot $ModelsPath $OutputPath $TreeOutputPath $ModelName | Out-Host if ($LASTEXITCODE -ne 0) { throw "Model reference graph generation failed with exit code $LASTEXITCODE." } + [pscustomobject]@{ + GraphPath = (Resolve-Path -LiteralPath $OutputPath).Path + TreePath = (Resolve-Path -LiteralPath $TreeOutputPath).Path + } } finally { - Remove-Item $temporaryScript -Force -ErrorAction SilentlyContinue + if (Test-Path -LiteralPath $temporaryScript) { + Remove-Item -LiteralPath $temporaryScript -Force + } } \ 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 7f18fa75ba0c..b8c248424a5b 100644 --- a/sdk/ai/azure-ai-projects/CHANGELOG.md +++ b/sdk/ai/azure-ai-projects/CHANGELOG.md @@ -1,5 +1,62 @@ # Release History +## 2.11.0 (2026-11-10) + +### Features Added + +* Added preview `.beta.voice_agents.live.connect()` and `VoiceAgentLiveDefinition` for synchronous and asynchronous GPT Live sessions, with typed client and server events, session updates, text and audio input, and Responses backend function-tool support. +* Added Live delegation models for Responses backends, application-managed work, and same-project prompt agents: `VoiceAgentLiveResponsesDelegation`, `VoiceAgentLiveClientDelegation`, and `VoiceAgentLiveManagedAgentDelegation`. +* Added `.beta.voice_agents.live_conversations` for listing, retrieving, and deleting stored Live conversations, retrieving conversation items, and retrieving or downloading item-level and conversation-level audio. +* Added optional `VoiceAgentDefinition.post_call` with `VoiceAgentPostCallConfig`, `VoiceAgentEventGridPostCallDestination`, and `VoiceAgentRoutinePostCallDestination` for post-call transcript delivery to Event Grid connections and routines. Audio delivery is not supported in this preview. +* Added SIP telephony provider support through `TelephonyProvider.SIP`, `SipTelephonyBinding`, and `SipTelephonyBindingListItem`. Added optional `UpdateTelephonyBindingRequest.allowed_calling_numbers` for incoming caller restrictions. +* Added `.beta.voice_agents.telephony.list_call_jobs()` for listing outbound call jobs with optional status and campaign filters, and `.beta.voice_agents.telephony.delete_call_job()` for deleting a call job. +* Added `.beta.voice_agents.campaigns` for managing outbound campaigns, including long-running creation, cancellation, and deletion, campaign retrieval and listing, validation errors, and operation status. Campaign mutations support ETag match conditions. +* Added campaign configuration, scheduling, and progress models, including `TelephonyCampaign`, `TelephonyRecipient`, `ImmediateSchedule`, `AtTimeSchedule`, `PerRecipientSchedule`, and `TelephonyCampaignProgress`. `TelephonyCampaignDatasetReference` supports an optional version that pins the latest dataset version during campaign preparation when omitted. Added optional read-only `TelephonyCallJob.campaign_name`. +* Added inline Voice Agent subagents and handoff configuration through `VoiceAgentInlineSubagentConfig`, `InlineVoiceSubagent`, and `VoiceAgentHandoffPolicy`, with handoff lifecycle events and optional `VoiceAgentSessionResponseConfig.handoff`. +* Added Voice Agent system tools `VoiceAgentTransferSystemTool`, `VoiceAgentSendDtmfSystemTool`, `VoiceAgentSendSmsSystemTool`, `VoiceAgentCollectDtmfSystemTool`, `VoiceAgentCollectSmsSystemTool`, `VoiceAgentDigitRecognitionSystemTool`, and `VoiceAgentLanguageDetectionSystemTool`. +* Added optional `VoiceAgentSystemTool.timeout_seconds`, also available on `VoiceAgentEndConversationSystemTool`, for configuring execution timeouts. +* Added realtime system-tool intent items and argument-streaming and input-collection events through `VoiceAgentSystemToolItem`, `VoiceAgentServerEventSystemToolArgumentsDelta`, `VoiceAgentServerEventSystemToolArgumentsDone`, and `VoiceAgentServerEventInputCollectionStatus`. +* Added `VoiceAgentBaseDefinition`, `VoiceAgentVoiceConfig`, and `VoiceAgentSubProtocol` for shared voice configuration and Realtime/Live definition types. Added extensible enums for tool types, greetings, interim responses, conversation engines, and RTC call errors. +* Added optional error details `MisalignmentErrorDetailsResource.review_target` and `RealtimeResponseStatusDetailsError.message`. +* Expanded `ImageGenTool.model` known-value annotations to include the `gpt-image-2.5-sunburst` and `gpt-image-2.5-flare` model families and their dated versions, and `ImageGenTool.quality` to include `xhigh` and `max`. +* Added explicit recursive typing for nested `CompoundFilter` instances in `CompoundFilter.filters`. + +### Breaking Changes + +All breaking changes affect preview APIs. + +Breaking changes in beta methods: + +* Argument `telephony_binding` in `.beta.voice_agents.telephony.create_binding()` renamed to `binding`; the typed body now accepts `TelephonyBinding` instead of `CreateTelephonyBindingRequest`. +* Argument `body` in `.beta.voice_agents.telephony.create_call_job()` renamed to `job`; the typed body now accepts `TelephonyCallJobCreate` instead of `CreateTelephonyCallJobRequest`. +* Removed the `status` filter from `.beta.voice_agents.telephony.list_bindings()`. + +Breaking changes in beta classes: + +* Removed `CreateTelephonyBindingRequest`, `CreateTeamsPhoneExtensibilityTelephonyBindingRequest`, and `CreateTwilioTelephonyBindingRequest`. Use `TelephonyBinding`, `TeamsPhoneExtensibilityTelephonyBinding`, and `TwilioTelephonyBinding`, respectively. +* Class `CreateTelephonyCallJobRequest` renamed to `TelephonyCallJobCreate`. +* Removed `TelephonyOutboundDestination` and `TelephonyOutboundDestinationType`; use `TelephonyAddress` and `TelephonyAddressType`. The `source` and `destination` properties on `TelephonyCallJobCreate` and `TelephonyCallJob` now use `TelephonyAddress`; `source` no longer accepts a plain string. +* Removed `TelephonyTransferDestination`, `PSTNTelephonyTransferDestination`, `SipTelephonyTransferDestination`, `TeamsTelephonyTransferDestination`, and `TelephonyTransferDestinationKind`. `TelephonyTransferTarget.destination` now uses `TelephonyAddress`, with `PhoneNumber`, `SipAddress`, and `TeamsAddress` variants and `TelephonyAddressType`. The discriminator is `type` instead of `kind`, and the PSTN value is `phone_number` instead of `pstn`. +* Class `TelephonyOutboundFixedIntervalRetryPolicy` renamed to `FixedIntervalRetryPolicy`. +* Removed `TelephonyBindingStatus` and the `status` property from `TelephonyBinding`, `TelephonyBindingListItem`, their existing provider-specific subclasses, and `UpdateTelephonyBindingRequest`. +* Properties `TelephonyBinding.id` and `TelephonyBinding.incoming_call_url` are now read-only, including inherited properties on provider-specific bindings. +* Removed `TelephonyCallJob.object`. Properties `id`, `agent_name`, `status`, `cancellation`, `attempt_count`, `next_attempt_at`, `terminal_reason`, `revision`, `created_at`, and `updated_at` are now read-only. +* `VoiceAgentSubagentConfig` is now a polymorphic base requiring `subagent_type` instead of `subagents`. Use `VoiceAgentDelegateSubagentConfig` for the previous referenced-agent configuration, or `VoiceAgentInlineSubagentConfig` for inline subagents. +* `VoiceAgentResponseCreateParams.input` now uses dedicated response-input models (`RealtimeResponseInputMessage`, `RealtimeResponseInputFunctionCall`, `RealtimeResponseInputFunctionCallOutput`, and `RealtimeResponseItemReference`) instead of `RealtimeConversationItem`. +* Constructor argument `timestamp_type` on `VoiceAgentServerEventResponseAudioTimestampDelta` is now required; use `VoiceAgentAudioTimestampType.WORD`. +* Constructor arguments `left` and `right` on `VoiceRecordingChannelLayout` are now required; use `VoiceAudioRole.USER` and `VoiceAudioRole.AGENT`, respectively. + +### Bugs Fixed + +### Sample updates + +* Added Live voice-agent samples under `samples/agents/voice/` for session lifecycle, text and audio conversations, local function tools, and same-project managed-agent delegation. +* Added `sample_voice_agent_live_read_conversation.py` demonstrating stored Live conversation, transcript, and audio retrieval, with an optional temporary greeting session. +* Added `sample_voice_agent_read_generated_audio.py` demonstrating retrieval of generated, unheard audio from an interrupted Realtime reply. +* Added a Realtime interruption sample demonstrating response cancellation and conversation-item truncation. +* Updated existing Voice Agent sample descriptions, configuration guidance, and cleanup instructions. +* Consolidated the Realtime text-conversation and function-tool examples into their asynchronous samples, and removed the separate asynchronous basic agent sample. + ## 2.10.0 (2026-10-30) ### Features Added diff --git a/sdk/ai/azure-ai-projects/PostEmitter.ps1 b/sdk/ai/azure-ai-projects/PostEmitter.ps1 index ee2644b22ca3..f07b9f8d327c 100644 --- a/sdk/ai/azure-ai-projects/PostEmitter.ps1 +++ b/sdk/ai/azure-ai-projects/PostEmitter.ps1 @@ -131,15 +131,48 @@ foreach ($f in $files) { } # Fix Sphinx docutils warnings in get_session_log_stream docstrings (sync + async). -# The emitter wraps bullet/code-block lines with insufficient indentation. +# The pinned TypeSpec docs have correct indentation; the producing emitter version is unverified. +# Follow up by reporting the wrapping to microsoft/typespec with the tsp-location.yaml inputs. +# Remove this workaround when the emitter preserves bullet continuations and SSE data lines. +function Repair-SessionLogDocstring { + param([string]$Content) + + $pattern = '(?ms)^ (?:async )?def get_session_log_stream\(.*?^ """.*?^ """' + [regex]::Replace($Content, $pattern, { + param($docstring) + + $newLine = if ($docstring.Value.Contains("`r`n")) { "`r`n" } else { "`n" } + $out = [System.Collections.Generic.List[string]]::new() + $bulletIndent = $null + $dataIndent = $null + foreach ($line in [regex]::Split($docstring.Value, '\r?\n')) { + $trimmed = $line.TrimStart() + $indent = $line.Length - $trimmed.Length + if (-not $trimmed -or $trimmed -match '^(?:\*\s|\.\.\s|:\w|"""|event:|data:)') { + $bulletIndent = $null + $dataIndent = $null + } + if ($null -ne $dataIndent -and $indent -lt $dataIndent) { + $out[$out.Count - 1] += ' ' + $trimmed + continue + } + $dataIndent = if ($trimmed.StartsWith('data: ')) { $indent } else { $null } + if ($trimmed -match '^\*\s') { + $bulletIndent = $indent + } + elseif ($null -ne $bulletIndent -and $indent -lt $bulletIndent + 2) { + $line = (' ' * ($bulletIndent + 2)) + $trimmed + } + $out.Add($line) + } + $out -join $newLine + }) +} + $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' + $c = Repair-SessionLogDocstring -Content $c Set-Content $f $c -NoNewline } diff --git a/sdk/ai/azure-ai-projects/README.md b/sdk/ai/azure-ai-projects/README.md index c6d5e28f1331..c7dda7b377de 100644 --- a/sdk/ai/azure-ai-projects/README.md +++ b/sdk/ai/azure-ai-projects/README.md @@ -199,9 +199,8 @@ The table below lists the operation groups supported by the client library, with ### Voice Agent realtime transport (preview) -Select the connection transport with the optional `transport` keyword. The SDK constructs the wire -query internally; callers do not need to put the transport in `extra_query`. Omitting the option -preserves the service's default WebSocket behavior. +Use `project_client.beta.voice_agents.realtime` for agents created with `VoiceAgentDefinition`. +Connections use WebSocket by default. You can also select the transport explicitly: ```python from azure.ai.projects.models import VoiceAgentTransport @@ -223,9 +222,77 @@ async with async_project_client.beta.voice_agents.realtime.connect( print("Voice Agent connection is ready.") ``` -`VoiceAgentTransport.WEBRTC` selects WebRTC signaling over the WebSocket. The application must manage -the peer connection, media, and SDP offer/answer exchange using `rtc.call.sdp.create` and -`rtc.call.sdp.created` events. Selecting this value does not automatically create a WebRTC media client. +Use `transport`, not `extra_query`, to select a transport. `VoiceAgentTransport.WEBRTC` enables +WebRTC signaling over the WebSocket, but your app must handle the peer connection, audio/video, +and SDP offer/answer exchange (`rtc.call.sdp.create` and `rtc.call.sdp.created`). + +Start with the [text conversation sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation_async.py) +or [microphone sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_audio_conversation_async.py). +The [async interruption sample](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_interruption_async.py) +cancels a spoken response and confirms truncation over the WebSocket. +It requires no audio devices: because it plays no audio, it reports zero heard milliseconds. +A real player must report its actual playback position. +The separate [sync REST example](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_generated_audio.py) +reads an existing generated-audio artifact and optionally saves it to a new output file. +It requires the stored item ID from REST and a deployment that persists unheard audio. + +### Voice Agent GPT Live (preview) + +Use `.beta.voice_agents.live` for GPT Live sessions and `.beta.voice_agents.live_conversations` +for their stored conversations. Realtime uses separate clients and agent definitions. + +**Get started** + +1. Install the sample dependencies: + +```powershell +pip install "azure-ai-projects[voice]" azure-identity python-dotenv +``` + +2. Set `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_VOICE_AGENT_MODEL` in your environment or `.env`. + The model value must be your GPT Live **deployment name**, not a model catalog ID. +3. Choose an example below and follow its `USAGE` instructions. Samples authenticate with + `DefaultAzureCredential` and opt in to preview features. + +**Choose an example** + +| Task | Example | Additional settings | +|---|---|---| +| Open, update, and close a session | [Async connection](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_connection_async.py) | None | +| Send text messages | [Async text](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py) | `FOUNDRY_MODEL_NAME` for the Responses backend | +| Run a local function tool | [Async function tool](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool_async.py) | `FOUNDRY_MODEL_NAME` for the Responses backend | +| Ask a same-project prompt agent a spoken question | [Async managed agent](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_managed_agent_async.py) | `FOUNDRY_MODEL_NAME` for the prompt agent | +| Send a WAV file or use a microphone | [Async audio](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py) | None; a spoken question is included | +| Read a stored conversation and download audio | [Sync REST readback](https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_read_conversation.py) | Optional existing conversation and agent IDs | + +**Inputs and cleanup** + +- Audio examples use the included `audio/question.wav`; no input-path setting or audio device + is needed. It asks, "What is two plus two? Please ask the backend agent to answer my question." + To use your own **PCM16, mono, 24-kHz WAV**, set `FOUNDRY_VOICE_AUDIO_INPUT_PATH`. + The managed-agent example accepts up to 30 seconds and creates both agents in the same project. + For microphone mode, install `pyaudio` and set `USE_MICROPHONE = True`. +- For multiple text turns, set `TEXT_PROMPTS` in the text example. The examples delete only + resources they create; existing agents and conversations are never changed by REST readback. +- To read an existing stored conversation, set `FOUNDRY_VOICE_AGENT_NAME` and + `FOUNDRY_VOICE_CONVERSATION_ID`. Use the ID from `session.started.conversation_id`, not + `session.id`, after a session with `store=True`. Without an ID, the REST example creates + and cleans up its own greeting conversation. +- Audio is not saved by default. `SAVE_AUDIO = True` saves replies in the audio example; + REST downloads use a unique temporary folder. These files contain conversation content; + remove them when finished. Customer-storage (BYOS) audio requires your own storage credentials. + +**Session notes** + +- Wait for `session.started` before sending commands. Foundry starts the session automatically. + To finish, send `session.close` and wait for `session.closed`; Live has no `response.cancel`. +- Keep input audio paced while waiting for context updates. The connection example sends + silent frames for this purpose; it needs no microphone. +- Responses commands require a Responses backend. Foundry handles managed-agent delegation; + the client must not answer those requests itself. Session updates cannot change the saved + delegation target, frontend model, or audio format. +- Printed backend text is not proof that speech finished. Audio examples wait for three + quiet seconds, so a long pause can end capture early. Unsupported REST routes return HTTP 404. ## Client-side tracing @@ -293,7 +360,8 @@ openai_logger.setLevel(logging.DEBUG) openai_logger.propagate = False openai_logger.addHandler(handler) -# Optional: Voice Agent WebSocket transport logger. +# Optional: Voice Agent Realtime WebSocket transport logger. +# For GPT Live, use "azure.ai.projects.live" instead. voice_logger = logging.getLogger("azure.ai.projects.realtime") voice_logger.setLevel(logging.DEBUG) voice_logger.propagate = False @@ -304,7 +372,7 @@ voice_logger.addHandler(handler) # handler.setFormatter(formatter) ``` -The `azure` logger includes logs from `azure-ai-projects` and `azure-core`, including Voice Agent WebSocket transport logs. The dedicated OpenAI and Voice Agent loggers shown above can be used when you want only those transport logs. At `DEBUG` level, the Voice Agent logger records connection and close events and the type and byte count of each event sent or received. It does not log event payloads, URL query strings, request headers, or authentication tokens. +The `azure` logger includes logs from `azure-ai-projects` and `azure-core`, including Voice Agent WebSocket transport logs. The dedicated OpenAI and Voice Agent loggers shown above can be used when you want only those transport logs. The `azure.ai.projects.realtime` and `azure.ai.projects.live` loggers record connection and close events and the type and byte count of each event sent or received at `DEBUG` level. They do not log event payloads, URL query strings, request headers, or authentication tokens. By default, logs redact URL query values, some HTTP request and response headers (including `Authorization`), and request and response payloads. To create HTTP pipeline logs without redaction, add `logging_enable=True` to the client constructor: diff --git a/sdk/ai/azure-ai-projects/api.md b/sdk/ai/azure-ai-projects/api.md index 84ed78a467fa..235f3e562a6b 100644 --- a/sdk/ai/azure-ai-projects/api.md +++ b/sdk/ai/azure-ai-projects/api.md @@ -635,6 +635,68 @@ namespace azure.ai.projects.aio.operations ) -> SessionFileWriteResult: ... + class azure.ai.projects.aio.operations.AsyncBetaLive: + + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + def connect( + self, + *, + agent_name: str, + agent_version: Optional[str] = ..., + api_version: Optional[str] = ..., + connection_url: Optional[str] = ..., + credential_scopes: Optional[list[str]] = ..., + extra_headers: Optional[Mapping[str, str]] = ..., + extra_query: Optional[Mapping[str, str]] = ..., + store: Optional[bool] = ..., + structured_inputs: Optional[Mapping[str, Any]] = ..., + **kwargs: Any + ) -> AsyncBetaLiveConnectionManager: ... + + + class azure.ai.projects.aio.operations.AsyncBetaLiveConnection(_BaseWebSocketConnection[LiveServerEvent, LiveClientEvent]): implements AsyncContextManager + property closed: bool # Read-only + + def __aiter__(self) -> AsyncIterator[LiveServerEvent]: ... + + def __init__( + self, + connection: ClientWebSocketResponse, + session: ClientSession + ) -> None: ... + + def __repr__(self) -> str: ... + + async def close( + self, + *, + code: int = 1000, + reason: str = "" + ) -> None: ... + + async def recv(self) -> LiveServerEvent: ... + + async def send(self, event: LiveClientEvent) -> None: ... + + + class azure.ai.projects.aio.operations.AsyncBetaLiveConnectionManager(_BaseWebSocketConnectionManager[AsyncBetaLiveConnection]): implements AsyncContextManager + + def __init__( + self, + *, + agent_version: Optional[str] = ..., + store: Optional[bool] = ..., + **kwargs: Any + ) -> None: ... + + async def enter(self) -> AsyncBetaLiveConnection: ... + + class azure.ai.projects.aio.operations.AsyncBetaRealtime: def __init__( @@ -659,7 +721,7 @@ namespace azure.ai.projects.aio.operations ) -> AsyncBetaRealtimeConnectionManager: ... - class azure.ai.projects.aio.operations.AsyncBetaRealtimeConnection: implements AsyncContextManager + class azure.ai.projects.aio.operations.AsyncBetaRealtimeConnection(_BaseWebSocketConnection[ServerEvent, ClientEvent]): implements AsyncContextManager property closed: bool # Read-only def __aiter__(self) -> AsyncIterator[ServerEvent]: ... @@ -684,7 +746,7 @@ namespace azure.ai.projects.aio.operations async def send(self, event: ClientEvent) -> None: ... - class azure.ai.projects.aio.operations.AsyncBetaRealtimeConnectionManager: implements AsyncContextManager + class azure.ai.projects.aio.operations.AsyncBetaRealtimeConnectionManager(_BaseWebSocketConnectionManager[AsyncBetaRealtimeConnection]): implements AsyncContextManager def __init__( self, @@ -2024,6 +2086,122 @@ namespace azure.ai.projects.aio.operations ) -> SkillDetails: ... + class azure.ai.projects.aio.operations.BetaVoiceAgentsCampaignsOperations(GeneratedBetaVoiceAgentsCampaignsOperations): + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + async def begin_cancel( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[TelephonyCampaign]: ... + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: TelephonyCampaign, + *, + content_type: str = "application/json", + etag: Optional[str] = ..., + match_condition: Optional[MatchConditions] = ..., + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[TelephonyCampaign]: ... + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: JSON, + *, + content_type: str = "application/json", + etag: Optional[str] = ..., + match_condition: Optional[MatchConditions] = ..., + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[TelephonyCampaign]: ... + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: IO[bytes], + *, + content_type: str = "application/json", + etag: Optional[str] = ..., + match_condition: Optional[MatchConditions] = ..., + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[TelephonyCampaign]: ... + + async def begin_delete( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[None]: ... + + @distributed_trace_async + async def get( + self, + agent_name: str, + campaign_name: str, + *, + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> TelephonyCampaign: ... + + @distributed_trace_async + async def get_operation( + self, + agent_name: str, + campaign_name: str, + operation_id: str, + **kwargs: Any + ) -> TelephonyCampaignOperation: ... + + @distributed_trace + def list( + self, + agent_name: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + status: Optional[Union[str, TelephonyCampaignStatus]] = ..., + **kwargs: Any + ) -> AsyncItemPaged[TelephonyCampaign]: ... + + @distributed_trace + def list_validation_errors( + self, + agent_name: str, + campaign_name: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + **kwargs: Any + ) -> AsyncItemPaged[TelephonyCampaignValidationError]: ... + + class azure.ai.projects.aio.operations.BetaVoiceAgentsConversationsOperations: def __init__( @@ -2167,8 +2345,102 @@ namespace azure.ai.projects.aio.operations ) -> AsyncItemPaged[VoiceResponse]: ... + class azure.ai.projects.aio.operations.BetaVoiceAgentsLiveConversationsOperations: + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + @distributed_trace_async + async def delete( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace_async + async def download_audio( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> AsyncIterator[bytes]: ... + + @distributed_trace_async + async def download_audio_item( + self, + agent_name: str, + conversation_id: str, + item_id: str, + **kwargs: Any + ) -> AsyncIterator[bytes]: ... + + @distributed_trace_async + async def get( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> VoiceAgentLiveConversation: ... + + @distributed_trace_async + async def get_audio( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> VoiceRecording: ... + + @distributed_trace_async + async def get_audio_item( + self, + agent_name: str, + conversation_id: str, + item_id: str, + **kwargs: Any + ) -> VoiceAudioItem: ... + + @distributed_trace_async + async def get_item( + self, + agent_name: str, + conversation_id: str, + item_id: str, + **kwargs: Any + ) -> VoiceAgentLiveConversationItem: ... + + @distributed_trace + def list( + self, + agent_name: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + **kwargs: Any + ) -> AsyncItemPaged[VoiceAgentLiveConversation]: ... + + @distributed_trace + def list_items( + self, + agent_name: str, + conversation_id: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + **kwargs: Any + ) -> AsyncItemPaged[VoiceAgentLiveConversationItem]: ... + + class azure.ai.projects.aio.operations.BetaVoiceAgentsOperations(GeneratedBetaVoiceAgentsOperations): + campaigns: BetaVoiceAgentsCampaignsOperations conversations: BetaVoiceAgentsConversationsOperations + live: AsyncBetaLive + live_conversations: BetaVoiceAgentsLiveConversationsOperations realtime: AsyncBetaRealtime telephony: BetaVoiceAgentsTelephonyOperations @@ -2202,7 +2474,7 @@ namespace azure.ai.projects.aio.operations async def create_binding( self, agent_name: str, - telephony_binding: CreateTelephonyBindingRequest, + binding: TelephonyBinding, *, content_type: str = "application/json", **kwargs: Any @@ -2212,7 +2484,7 @@ namespace azure.ai.projects.aio.operations async def create_binding( self, agent_name: str, - telephony_binding: JSON, + binding: JSON, *, content_type: str = "application/json", **kwargs: Any @@ -2222,7 +2494,7 @@ namespace azure.ai.projects.aio.operations async def create_binding( self, agent_name: str, - telephony_binding: IO[bytes], + binding: IO[bytes], *, content_type: str = "application/json", **kwargs: Any @@ -2232,7 +2504,7 @@ namespace azure.ai.projects.aio.operations async def create_call_job( self, agent_name: str, - body: CreateTelephonyCallJobRequest, + job: TelephonyCallJobCreate, *, content_type: str = "application/json", idempotency_key: str, @@ -2243,7 +2515,7 @@ namespace azure.ai.projects.aio.operations async def create_call_job( self, agent_name: str, - body: JSON, + job: JSON, *, content_type: str = "application/json", idempotency_key: str, @@ -2254,7 +2526,7 @@ namespace azure.ai.projects.aio.operations async def create_call_job( self, agent_name: str, - body: IO[bytes], + job: IO[bytes], *, content_type: str = "application/json", idempotency_key: str, @@ -2272,6 +2544,14 @@ namespace azure.ai.projects.aio.operations **kwargs: Any ) -> None: ... + @distributed_trace_async + async def delete_call_job( + self, + agent_name: str, + call_job_id: str, + **kwargs: Any + ) -> None: ... + @distributed_trace_async async def end_call( self, @@ -2320,10 +2600,22 @@ namespace azure.ai.projects.aio.operations limit: Optional[int] = ..., order: Optional[Union[str, PageOrder]] = ..., provider: Optional[Union[str, TelephonyProvider]] = ..., - status: Optional[Union[str, TelephonyBindingStatus]] = ..., **kwargs: Any ) -> AsyncItemPaged[TelephonyBindingListItem]: ... + @distributed_trace + def list_call_jobs( + self, + agent_name: str, + *, + before: Optional[str] = ..., + campaign_name: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + status: Optional[Union[str, TelephonyCallJobStatus]] = ..., + **kwargs: Any + ) -> AsyncItemPaged[TelephonyCallJob]: ... + @distributed_trace def list_calls( self, @@ -4953,27 +5245,122 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ApiError(_Model): - additional_info: Optional[dict[str, Any]] - code: str - debug_info: Optional[dict[str, Any]] - details: Optional[list[ApiError]] - message: str - misalignment: Optional[MisalignmentErrorDetailsResource] - param: Optional[str] - type: Optional[str] + class azure.ai.projects.models.AnswerResource(_Model): + type: str @overload def __init__( self, *, - additional_info: Optional[dict[str, Any]] = ..., - code: str, - debug_info: Optional[dict[str, Any]] = ..., - details: Optional[list[ApiError]] = ..., - message: str, - misalignment: Optional[MisalignmentErrorDetailsResource] = ..., - param: Optional[str] = ..., + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.AnswerResourceChoice(AnswerResource, discriminator='choice'): + choice: ChoiceValueResource + confidence: float + name: str + probabilities: list[ChoiceProbabilityResource] + type: Literal[AnswerResourceType.CHOICE] + + @overload + def __init__( + self, + *, + choice: ChoiceValueResource, + confidence: float, + name: str, + probabilities: list[ChoiceProbabilityResource] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.AnswerResourcePredicate(AnswerResource, discriminator='predicate'): + name: str + probability: float + type: Literal[AnswerResourceType.PREDICATE] + + @overload + def __init__( + self, + *, + name: str, + probability: float + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.AnswerResourceRefusal(AnswerResource, discriminator='refusal'): + name: str + type: Literal[AnswerResourceType.REFUSAL] + + @overload + def __init__( + self, + *, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.AnswerResourceScore(AnswerResource, discriminator='score'): + confidence: float + name: str + probabilities: list[ScoreProbabilityResource] + score: float + type: Literal[AnswerResourceType.SCORE] + + @overload + def __init__( + self, + *, + confidence: float, + name: str, + probabilities: list[ScoreProbabilityResource], + score: float + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.AnswerResourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CHOICE = "choice" + PREDICATE = "predicate" + REFUSAL = "refusal" + SCORE = "score" + + + class azure.ai.projects.models.ApiError(_Model): + additional_info: Optional[dict[str, Any]] + code: str + debug_info: Optional[dict[str, Any]] + details: Optional[list[ApiError]] + message: str + misalignment: Optional[MisalignmentErrorDetailsResource] + param: Optional[str] + type: Optional[str] + + @overload + def __init__( + self, + *, + additional_info: Optional[dict[str, Any]] = ..., + code: str, + debug_info: Optional[dict[str, Any]] = ..., + details: Optional[list[ApiError]] = ..., + message: str, + misalignment: Optional[MisalignmentErrorDetailsResource] = ..., + param: Optional[str] = ..., type: Optional[str] = ... ) -> None: ... @@ -5155,6 +5542,23 @@ namespace azure.ai.projects.models ) -> AsyncUpdateMemoriesLROPoller: ... + class azure.ai.projects.models.AtTimeSchedule(TelephonyCampaignSchedule, discriminator='scheduled'): + expires_at: datetime + scheduled_at: datetime + type: Literal[TelephonyCampaignScheduleType.SCHEDULED] + + @overload + def __init__( + self, + *, + expires_at: Optional[datetime] = ..., + scheduled_at: datetime + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.AttackStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): ANSI_ATTACK = "ansi_attack" ASCII_ART = "ascii_art" @@ -5826,6 +6230,22 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.ChoiceProbabilityResource(_Model): + probability: float + value: ChoiceValueResource + + @overload + def __init__( + self, + *, + probability: float, + value: ChoiceValueResource + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.ClusterInsightResult(_Model): clusters: list[InsightCluster] coordinates: Optional[dict[str, ChartCoordinate]] @@ -5978,14 +6398,14 @@ namespace azure.ai.projects.models class azure.ai.projects.models.CompoundFilter(_Model): - filters: list[Union[ComparisonFilter, Any]] + filters: list[Union[ComparisonFilter, CompoundFilter]] type: Literal["and", "or"] @overload def __init__( self, *, - filters: list[Union[ComparisonFilter, Any]], + filters: list[Union[ComparisonFilter, CompoundFilter]], type: Literal["and", "or"] ) -> None: ... @@ -6263,71 +6683,6 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.CreateTeamsPhoneExtensibilityTelephonyBindingRequest(CreateTelephonyBindingRequest, discriminator='teams_phone_extensibility'): - connection_name: str - label: str - phone_number: Optional[str] - provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] - resource_account_object_id: str - - @overload - def __init__( - self, - *, - connection_name: str, - label: Optional[str] = ..., - phone_number: Optional[str] = ..., - resource_account_object_id: str - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.CreateTelephonyBindingRequest(_Model): - connection_name: str - label: Optional[str] - provider: str - - @overload - def __init__( - self, - *, - connection_name: str, - label: Optional[str] = ..., - provider: str - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.CreateTelephonyCallJobRequest(_Model): - connection_name: str - destination: TelephonyOutboundDestination - purpose: Optional[str] - retry_policy: Optional[TelephonyOutboundRetryPolicy] - schedule: Optional[TelephonyCallJobSchedule] - source: str - structured_inputs: Optional[dict[str, Any]] - - @overload - def __init__( - self, - *, - connection_name: str, - destination: TelephonyOutboundDestination, - purpose: Optional[str] = ..., - retry_policy: Optional[TelephonyOutboundRetryPolicy] = ..., - schedule: Optional[TelephonyCallJobSchedule] = ..., - source: str, - structured_inputs: Optional[dict[str, Any]] = ... - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.CreateTranscriptionResponseJsonUsage(_Model): type: str @@ -6347,25 +6702,6 @@ namespace azure.ai.projects.models TOKENS = "tokens" - class azure.ai.projects.models.CreateTwilioTelephonyBindingRequest(CreateTelephonyBindingRequest, discriminator='twilio'): - connection_name: str - label: str - phone_number: str - provider: Literal[TelephonyProvider.TWILIO] - - @overload - def __init__( - self, - *, - connection_name: str, - label: Optional[str] = ..., - phone_number: str - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.CredentialType(str, Enum, metaclass=CaseInsensitiveEnumMeta): AGENTIC_IDENTITY_PREVIEW = "AgenticIdentityToken_Preview" API_KEY = "ApiKey" @@ -6799,6 +7135,24 @@ namespace azure.ai.projects.models WEDNESDAY = "Wednesday" + class azure.ai.projects.models.DecisionResponse(_Model): + answers: list[AnswerResource] + model: str + usage: ResponseUsageResource + + @overload + def __init__( + self, + *, + answers: list[AnswerResource], + model: str, + usage: ResponseUsageResource + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.DeleteAgentResponse(_Model): deleted: bool name: str @@ -7946,6 +8300,23 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.FixedIntervalRetryPolicy(TelephonyOutboundRetryPolicy, discriminator='fixed_interval'): + interval: timedelta + max_attempts: int + type: Literal[TelephonyOutboundRetryPolicyType.FIXED_INTERVAL] + + @overload + def __init__( + self, + *, + interval: timedelta, + max_attempts: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.FixedRatioVersionSelectionRule(VersionSelectionRule, discriminator='FixedRatio'): agent_version: str traffic_percentage: int @@ -8423,13 +8794,13 @@ namespace azure.ai.projects.models description: Optional[str] input_fidelity: Optional[Union[str, InputFidelity]] input_image_mask: Optional[ImageGenToolInputImageMask] - model: Optional[Union[Literal["gpt-image-1"], Literal["gpt-image-1-mini"], Literal["gpt-image-5"], Literal["gpt-image-2"], Literal["gpt-image-2-2026-04-21"], str]] + model: Optional[Union[Literal["gpt-image-1"], Literal["gpt-image-1-mini"], Literal["gpt-image-5"], Literal["gpt-image-2"], Literal["gpt-image-2-2026-04-21"], Literal["gpt-image-5-sunburst"], Literal["gpt-image-5-sunburst-2026-09-08"], Literal["gpt-image-5-flare"], Literal["gpt-image-5-flare-2026-09-08"], str]] moderation: Optional[Literal["auto", "low"]] name: Optional[str] output_compression: Optional[int] output_format: Optional[Literal["png", "webp", "jpeg"]] partial_images: Optional[int] - quality: Optional[Literal["low", "medium", "high", "auto"]] + quality: Optional[Literal["low", "medium", "high", "xhigh", "max", "auto"]] size: Optional[Union[Literal["1024x1024"], Literal["1024x1536"], Literal["1536x1024"], Literal["auto"], str]] tool_configs: Optional[dict[str, ToolConfig]] type: Literal[ToolType.IMAGE_GENERATION] @@ -8443,13 +8814,13 @@ namespace azure.ai.projects.models description: Optional[str] = ..., input_fidelity: Optional[Union[str, InputFidelity]] = ..., input_image_mask: Optional[ImageGenToolInputImageMask] = ..., - model: Optional[Union[Literal[gpt-image-1], Literal[gpt-image-1-mini], Literal[gpt-image-5], Literal[gpt-image-2], Literal[gpt-image-2-2026-04-21], str]] = ..., + model: Optional[Union[Literal[gpt-image-1], Literal[gpt-image-1-mini], Literal[gpt-image-5], Literal[gpt-image-2], Literal[gpt-image-2-2026-04-21], Literal[gpt-image-5-sunburst], Literal[gpt-image-5-sunburst-2026-09-08], Literal[gpt-image-5-flare], Literal[gpt-image-5-flare-2026-09-08], str]] = ..., moderation: Optional[Literal[auto, low]] = ..., name: Optional[str] = ..., output_compression: Optional[int] = ..., output_format: Optional[Literal[png, webp, jpeg]] = ..., partial_images: Optional[int] = ..., - quality: Optional[Literal[low, medium, high, auto]] = ..., + quality: Optional[Literal[low, medium, high, xhigh, max, auto]] = ..., size: Optional[Union[Literal[1024x1024], Literal[1024x1536], Literal[1536x1024], Literal[auto], str]] = ..., tool_configs: Optional[dict[str, ToolConfig]] = ... ) -> None: ... @@ -8474,6 +8845,21 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.ImmediateSchedule(TelephonyCampaignSchedule, discriminator='immediate'): + expires_at: datetime + type: Literal[TelephonyCampaignScheduleType.IMMEDIATE] + + @overload + def __init__( + self, + *, + expires_at: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.Index(_Model): description: Optional[str] id: Optional[str] @@ -8536,25 +8922,85 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.InputFidelity(str, Enum, metaclass=CaseInsensitiveEnumMeta): - HIGH = "high" - LOW = "low" - - - class azure.ai.projects.models.Insight(_Model): - display_name: str - insight_id: str - metadata: InsightsMetadata - request: InsightRequest - result: Optional[InsightResult] - state: Union[str, OperationState] + class azure.ai.projects.models.InlineVoiceSubagent(_Model): + audio_output: Optional[VoiceAgentVoiceConfig] + display_description: str + handoff_conditions: Optional[list[VoiceAgentHandoffCondition]] + id: str + inherit_base_instructions: Optional[bool] + instructions: Optional[str] + interface: Literal["voice"] + interim_response: Optional[VoiceAgentInterimResponseConfig] + max_response_output_tokens: Optional[VoiceAgentHandoffMaxOutputTokens] + model: Optional[str] + parallel_tool_calls: Optional[bool] + reasoning_effort: Optional[Union[str, VoiceAgentHandoffReasoningEffort]] + source: Literal["inline"] + temperature: Optional[float] + tool_choice: Optional[VoiceAgentToolChoice] + tools: Optional[list[VoiceAgentTool]] + voice_adaptation: Optional[VoiceAgentHandoffVoiceAdaptation] @overload def __init__( self, *, - display_name: str, - request: InsightRequest + audio_output: Optional[VoiceAgentVoiceConfig] = ..., + display_description: str, + handoff_conditions: Optional[list[VoiceAgentHandoffCondition]] = ..., + id: str, + inherit_base_instructions: Optional[bool] = ..., + instructions: Optional[str] = ..., + interim_response: Optional[VoiceAgentInterimResponseConfig] = ..., + max_response_output_tokens: Optional[VoiceAgentHandoffMaxOutputTokens] = ..., + model: Optional[str] = ..., + parallel_tool_calls: Optional[bool] = ..., + reasoning_effort: Optional[Union[str, VoiceAgentHandoffReasoningEffort]] = ..., + temperature: Optional[float] = ..., + tool_choice: Optional[VoiceAgentToolChoice] = ..., + tools: Optional[list[VoiceAgentTool]] = ..., + voice_adaptation: Optional[VoiceAgentHandoffVoiceAdaptation] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.InputFidelity(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + + + class azure.ai.projects.models.InputTokensDetailsResource(_Model): + cache_write_tokens: int + cached_tokens: int + + @overload + def __init__( + self, + *, + cache_write_tokens: int, + cached_tokens: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.Insight(_Model): + display_name: str + insight_id: str + metadata: InsightsMetadata + request: InsightRequest + result: Optional[InsightResult] + state: Union[str, OperationState] + + @overload + def __init__( + self, + *, + display_name: str, + request: InsightRequest ) -> None: ... @overload @@ -8798,965 +9244,873 @@ namespace azure.ai.projects.models SUCCEEDED = "succeeded" - class azure.ai.projects.models.LocalShellToolParam(Tool, discriminator='local_shell'): - description: Optional[str] - name: Optional[str] - tool_configs: Optional[dict[str, ToolConfig]] - type: Literal[ToolType.LOCAL_SHELL] + class azure.ai.projects.models.LiveAllowedServerEventParam(_Model): + response_event: Optional[str] + type: str @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ... + response_event: Optional[str] = ..., + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.LocalSkillParam(_Model): - description: str - name: str - path: str + class azure.ai.projects.models.LiveAllowedToolsChoiceParam(_Model): + mode: Optional[Union[str, LiveToolChoiceValueEnum]] + tools: list[Union[LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam]] + type: Literal["allowed_tools"] @overload def __init__( self, *, - description: str, - name: str, - path: str + mode: Optional[Union[str, LiveToolChoiceValueEnum]] = ..., + tools: list[Union[LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam]] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.LogProbProperties(_Model): - bytes: list[int] - logprob: float - token: str + class azure.ai.projects.models.LiveApplyPatchToolInputParam(_Model): + type: Literal["apply_patch"] + + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + + class azure.ai.projects.models.LiveAudioFormat(_Model): + type: str @overload def __init__( self, *, - bytes: list[int], - logprob: float, - token: str + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.LoraConfig(_Model): - alpha: Optional[int] - dropout: Optional[float] - rank: Optional[int] - target_modules: Optional[list[str]] + class azure.ai.projects.models.LiveAudioFormatType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUDIO_PCM = "audio/pcm" + AUDIO_PCMA = "audio/pcma" + AUDIO_PCMU = "audio/pcmu" + + + class azure.ai.projects.models.LiveClientConfigParam(_Model): + data_channel: LiveDataChannelConfigParam @overload def __init__( self, *, - alpha: Optional[int] = ..., - dropout: Optional[float] = ..., - rank: Optional[int] = ..., - target_modules: Optional[list[str]] = ... + data_channel: LiveDataChannelConfigParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MCPListToolsTool(_Model): - annotations: Optional[MCPListToolsToolAnnotations] - description: Optional[str] - input_schema: MCPListToolsToolInputSchema - name: str + class azure.ai.projects.models.LiveClientEvent(_Model): + type: str @overload def __init__( self, *, - annotations: Optional[MCPListToolsToolAnnotations] = ..., - description: Optional[str] = ..., - input_schema: MCPListToolsToolInputSchema, - name: str + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MCPListToolsToolAnnotations(_Model): + class azure.ai.projects.models.LiveClientEventLiveCommentaryAppendParam(LiveClientEvent, discriminator='session.commentary.append'): + content: str + delegation_id: str + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_COMMENTARY_APPEND] + @overload + def __init__( + self, + *, + content: str, + delegation_id: str, + event_id: Optional[str] = ... + ) -> None: ... - class azure.ai.projects.models.MCPListToolsToolInputSchema(_Model): + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MCPTool(Tool, discriminator='mcp'): - allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] - allowed_tools: Optional[Union[list[str], MCPToolFilter]] - authorization: Optional[str] - connector_id: Optional[Literal["connector_dropbox", "connector_gmail", "connector_googlecalendar", "connector_googledrive", "connector_microsoftteams", "connector_outlookcalendar", "connector_outlookemail", "connector_sharepoint"]] - defer_loading: Optional[bool] - headers: Optional[dict[str, str]] - project_connection_id: Optional[str] - require_approval: Optional[Union[MCPToolRequireApproval, Literal["always"], Literal["never"]]] - server_description: Optional[str] - server_label: str - server_url: Optional[str] - tool_configs: Optional[dict[str, ToolConfig]] - tunnel_id: Optional[str] - type: Literal[ToolType.MCP] + class azure.ai.projects.models.LiveClientEventLiveDecisionCreateParam(LiveClientEvent, discriminator='decision.create'): + event_id: str + type: Literal[LiveClientEventType.DECISION_CREATE] @overload def __init__( self, *, - allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] = ..., - allowed_tools: Optional[Union[list[str], MCPToolFilter]] = ..., - authorization: Optional[str] = ..., - connector_id: Optional[Literal[connector_dropbox, connector_gmail, connector_googlecalendar, connector_googledrive, connector_microsoftteams, connector_outlookcalendar, connector_outlookemail, connector_sharepoint]] = ..., - defer_loading: Optional[bool] = ..., - headers: Optional[dict[str, str]] = ..., - project_connection_id: Optional[str] = ..., - require_approval: Optional[Union[MCPToolRequireApproval, Literal[always], Literal[never]]] = ..., - server_description: Optional[str] = ..., - server_label: str, - server_url: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ..., - tunnel_id: Optional[str] = ... + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MCPToolFilter(_Model): - read_only: Optional[bool] - tool_names: Optional[list[str]] + class azure.ai.projects.models.LiveClientEventLiveDecisionItemCreateParam(LiveClientEvent, discriminator='decision.item.create'): + event_id: Optional[str] + item: LiveDecisionInputItemParam + type: Literal[LiveClientEventType.DECISION_ITEM_CREATE] @overload def __init__( self, *, - read_only: Optional[bool] = ..., - tool_names: Optional[list[str]] = ... + event_id: Optional[str] = ..., + item: LiveDecisionInputItemParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MCPToolRequireApproval(_Model): - always: Optional[MCPToolFilter] - never: Optional[MCPToolFilter] + class azure.ai.projects.models.LiveClientEventLiveDecisionItemDeleteParam(LiveClientEvent, discriminator='decision.item.delete'): + event_id: Optional[str] + item_id: str + type: Literal[LiveClientEventType.DECISION_ITEM_DELETE] @overload def __init__( self, *, - always: Optional[MCPToolFilter] = ..., - never: Optional[MCPToolFilter] = ... + event_id: Optional[str] = ..., + item_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MCPToolboxTool(ToolboxTool, discriminator='mcp'): - allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] - allowed_tools: Optional[Union[list[str], MCPToolFilter]] - authorization: Optional[str] - connector_id: Optional[Literal["connector_dropbox", "connector_gmail", "connector_googlecalendar", "connector_googledrive", "connector_microsoftteams", "connector_outlookcalendar", "connector_outlookemail", "connector_sharepoint"]] - defer_loading: Optional[bool] - description: str - headers: Optional[dict[str, str]] - name: str - project_connection_id: Optional[str] - require_approval: Optional[Union[MCPToolRequireApproval, Literal["always"], Literal["never"]]] - server_description: Optional[str] - server_label: str - server_url: Optional[str] - tool_configs: dict[str, ToolConfig] - tunnel_id: Optional[str] - type: Literal[ToolboxToolType.MCP] + class azure.ai.projects.models.LiveClientEventLiveInputAudioAppendEvent(LiveClientEvent, discriminator='session.input_audio.append'): + audio: str + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_INPUT_AUDIO_APPEND] @overload def __init__( self, *, - allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] = ..., - allowed_tools: Optional[Union[list[str], MCPToolFilter]] = ..., - authorization: Optional[str] = ..., - connector_id: Optional[Literal[connector_dropbox, connector_gmail, connector_googlecalendar, connector_googledrive, connector_microsoftteams, connector_outlookcalendar, connector_outlookemail, connector_sharepoint]] = ..., - defer_loading: Optional[bool] = ..., - description: Optional[str] = ..., - headers: Optional[dict[str, str]] = ..., - name: Optional[str] = ..., - project_connection_id: Optional[str] = ..., - require_approval: Optional[Union[MCPToolRequireApproval, Literal[always], Literal[never]]] = ..., - server_description: Optional[str] = ..., - server_label: str, - server_url: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ..., - tunnel_id: Optional[str] = ... + audio: str, + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ManagedAgentIdentityBlueprintReference(AgentBlueprintReference, discriminator='ManagedAgentIdentityBlueprint'): - blueprint_id: str - type: Literal[AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT] + class azure.ai.projects.models.LiveClientEventLiveInputAudioMuteParam(LiveClientEvent, discriminator='session.input_audio.mute'): + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_INPUT_AUDIO_MUTE] @overload def __init__( self, *, - blueprint_id: str + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ManagedAzureAISearchIndex(Index, discriminator='ManagedAzureSearch'): - description: str - id: str - name: str - tags: dict[str, str] - type: Literal[IndexType.MANAGED_AZURE_SEARCH] - vector_store_id: str - version: str + class azure.ai.projects.models.LiveClientEventLiveInputAudioUnmuteParam(LiveClientEvent, discriminator='session.input_audio.unmute'): + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_INPUT_AUDIO_UNMUTE] @overload def __init__( self, *, - description: Optional[str] = ..., - tags: Optional[dict[str, str]] = ..., - vector_store_id: str + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.McpProtocolConfiguration(_Model): - - - class azure.ai.projects.models.MemoryItem(_Model): + class azure.ai.projects.models.LiveClientEventLiveInstructionsAppendParam(LiveClientEvent, discriminator='session.instructions.append'): content: str - kind: str - memory_id: str - scope: str - updated_at: datetime + delegation_id: str + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_INSTRUCTIONS_APPEND] @overload def __init__( self, *, content: str, - kind: str, - memory_id: str, - scope: str, - updated_at: datetime + delegation_id: str, + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryItemKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CHAT_SUMMARY = "chat_summary" - PROCEDURAL = "procedural" - USER_PROFILE = "user_profile" - - - class azure.ai.projects.models.MemoryOperation(_Model): - kind: Union[str, MemoryOperationKind] - memory_item: MemoryItem + class azure.ai.projects.models.LiveClientEventLiveOutputAudioFixturePlayParam(LiveClientEvent, discriminator='session.output_audio.fixture.play'): + audio: str + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAY] @overload def __init__( self, *, - kind: Union[str, MemoryOperationKind], - memory_item: MemoryItem + audio: str, + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryOperationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CREATE = "create" - DELETE = "delete" - UPDATE = "update" - - - class azure.ai.projects.models.MemorySearchItem(_Model): - memory_item: MemoryItem + class azure.ai.projects.models.LiveClientEventLiveResponseCreateParam(LiveClientEvent, discriminator='response.create'): + event_id: Optional[str] + type: Literal[LiveClientEventType.RESPONSE_CREATE] @overload def __init__( self, *, - memory_item: MemoryItem + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemorySearchOptions(_Model): - max_memories: Optional[int] + class azure.ai.projects.models.LiveClientEventLiveResponseItemCreateParam(LiveClientEvent, discriminator='response.item.create'): + event_id: Optional[str] + item: dict[str, Any] + type: Literal[LiveClientEventType.RESPONSE_ITEM_CREATE] @overload def __init__( self, *, - max_memories: Optional[int] = ... + event_id: Optional[str] = ..., + item: dict[str, Any] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemorySearchPreviewTool(Tool, discriminator='memory_search_preview'): - memory_store_name: str - scope: str - search_options: Optional[MemorySearchOptions] - type: Literal[ToolType.MEMORY_SEARCH_PREVIEW] - update_delay: Optional[int] + class azure.ai.projects.models.LiveClientEventLiveSessionCloseParam(LiveClientEvent, discriminator='session.close'): + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_CLOSE] @overload def __init__( self, *, - memory_store_name: str, - scope: str, - search_options: Optional[MemorySearchOptions] = ..., - update_delay: Optional[int] = ... + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreDefaultDefinition(MemoryStoreDefinition, discriminator='default'): - chat_model: str - embedding_model: str - kind: Literal[MemoryStoreKind.DEFAULT] - options: Optional[MemoryStoreDefaultOptions] + class azure.ai.projects.models.LiveClientEventLiveSessionUpdateParam(LiveClientEvent, discriminator='session.update'): + event_id: Optional[str] + session: LiveSessionUpdateParams + type: Literal[LiveClientEventType.SESSION_UPDATE] @overload def __init__( self, *, - chat_model: str, - embedding_model: str, - options: Optional[MemoryStoreDefaultOptions] = ... + event_id: Optional[str] = ..., + session: LiveSessionUpdateParams ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreDefaultOptions(_Model): - chat_summary_enabled: bool - default_ttl_seconds: Optional[timedelta] - procedural_memory_enabled: Optional[bool] - user_profile_details: Optional[str] - user_profile_enabled: bool + class azure.ai.projects.models.LiveClientEventLiveThinkingAppendParam(LiveClientEvent, discriminator='session.thinking.append'): + content: str + delegation_id: str + event_id: Optional[str] + type: Literal[LiveClientEventType.SESSION_THINKING_APPEND] @overload def __init__( self, *, - chat_summary_enabled: bool, - default_ttl_seconds: Optional[timedelta] = ..., - procedural_memory_enabled: Optional[bool] = ..., - user_profile_details: Optional[str] = ..., - user_profile_enabled: bool + content: str, + delegation_id: str, + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreDefinition(_Model): - kind: str + class azure.ai.projects.models.LiveClientEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DECISION_CREATE = "decision.create" + DECISION_ITEM_CREATE = "decision.item.create" + DECISION_ITEM_DELETE = "decision.item.delete" + RESPONSE_CREATE = "response.create" + RESPONSE_ITEM_CREATE = "response.item.create" + SESSION_CLOSE = "session.close" + SESSION_COMMENTARY_APPEND = "session.commentary.append" + SESSION_INPUT_AUDIO_APPEND = "session.input_audio.append" + SESSION_INPUT_AUDIO_MUTE = "session.input_audio.mute" + SESSION_INPUT_AUDIO_UNMUTE = "session.input_audio.unmute" + SESSION_INSTRUCTIONS_APPEND = "session.instructions.append" + SESSION_OUTPUT_AUDIO_FIXTURE_PLAY = "session.output_audio.fixture.play" + SESSION_START = "session.start" + SESSION_THINKING_APPEND = "session.thinking.append" + SESSION_UPDATE = "session.update" + + + class azure.ai.projects.models.LiveCodeInterpreterToolInputParam(_Model): + type: Literal["code_interpreter"] - @overload def __init__( self, - *, - kind: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.LiveComputerToolInputParam(_Model): + type: Literal["computer"] - class azure.ai.projects.models.MemoryStoreDeleteScopeResult(_Model): - deleted: bool - name: str - object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED] - scope: str + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + + class azure.ai.projects.models.LiveContainerMemoryLimit(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ENUM_16_G = "16g" + ENUM_1_G = "1g" + ENUM_4_G = "4g" + ENUM_64_G = "64g" + + + class azure.ai.projects.models.LiveContainerNetworkPolicyDisabledParam(_Model): + type: Literal["disabled"] + + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + + class azure.ai.projects.models.LiveContainerReferenceParam(_Model): + container_id: str + type: Literal["container_reference"] @overload def __init__( self, *, - deleted: bool, - name: str, - object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED], - scope: str + container_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreDetails(_Model): - created_at: datetime - definition: MemoryStoreDefinition - description: Optional[str] - id: str - metadata: Optional[dict[str, str]] - name: str - object: Literal[MemoryStoreObjectType.MEMORY_STORE] - updated_at: datetime + class azure.ai.projects.models.LiveContextWindowUsage(_Model): + usage_ratio: float @overload def __init__( self, *, - created_at: datetime, - definition: MemoryStoreDefinition, - description: Optional[str] = ..., - id: str, - metadata: Optional[dict[str, str]] = ..., - name: str, - object: Literal[MemoryStoreObjectType.MEMORY_STORE], - updated_at: datetime + usage_ratio: float ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - DEFAULT = "default" - + class azure.ai.projects.models.LiveCustomToolInputParam(_Model): + type: Literal["custom"] - class azure.ai.projects.models.MemoryStoreObjectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - MEMORY_DELETED = "memory_store.item.deleted" - MEMORY_STORE = "memory_store" - MEMORY_STORE_DELETED = "memory_store.deleted" - MEMORY_STORE_SCOPE_DELETED = "memory_store.scope.deleted" + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... - class azure.ai.projects.models.MemoryStoreOperationUsage(_Model): - embedding_tokens: int - input_tokens: int - input_tokens_details: ResponseUsageInputTokensDetails - output_tokens: int - output_tokens_details: ResponseUsageOutputTokensDetails - total_tokens: int + class azure.ai.projects.models.LiveCustomVoiceParam(_Model): + id: str @overload def __init__( self, *, - embedding_tokens: int, - input_tokens: int, - input_tokens_details: ResponseUsageInputTokensDetails, - output_tokens: int, - output_tokens_details: ResponseUsageOutputTokensDetails, - total_tokens: int + id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreSearchResult(_Model): - memories: list[MemorySearchItem] - search_id: str - usage: MemoryStoreOperationUsage + class azure.ai.projects.models.LiveDataChannelConfigParam(_Model): + allowed_client_events: Optional[Union[Literal["all"], list[str]]] + allowed_server_events: Optional[Union[Literal["all"], list[LiveAllowedServerEventParam]]] @overload def __init__( self, *, - memories: list[MemorySearchItem], - search_id: str, - usage: MemoryStoreOperationUsage + allowed_client_events: Optional[Union[Literal[all], list[str]]] = ..., + allowed_server_events: Optional[Union[Literal[all], list[LiveAllowedServerEventParam]]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreUpdateCompletedResult(_Model): - memory_operations: list[MemoryOperation] - usage: MemoryStoreOperationUsage + class azure.ai.projects.models.LiveDecisionChoiceParam(_Model): + description: Optional[str] + value: Union[str, bool] @overload def __init__( self, *, - memory_operations: list[MemoryOperation], - usage: MemoryStoreOperationUsage + description: Optional[str] = ..., + value: Union[str, bool] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreUpdateResult(_Model): - error: Optional[ApiError] - result: Optional[MemoryStoreUpdateCompletedResult] - status: Union[str, MemoryStoreUpdateStatus] - superseded_by: Optional[str] - update_id: str + class azure.ai.projects.models.LiveDecisionChoiceQuestionParam(LiveDecisionQuestion, discriminator='choice'): + choices: list[LiveDecisionChoiceParam] + instructions: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam, LiveDecisionInputJsonParam]]] + name: Optional[str] + type: Literal[LiveDecisionQuestionType.CHOICE] @overload def __init__( self, *, - error: Optional[ApiError] = ..., - result: Optional[MemoryStoreUpdateCompletedResult] = ..., - status: Union[str, MemoryStoreUpdateStatus], - superseded_by: Optional[str] = ..., - update_id: str + choices: list[LiveDecisionChoiceParam], + instructions: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam, LiveDecisionInputJsonParam]]], + name: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MemoryStoreUpdateStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - COMPLETED = "completed" - FAILED = "failed" - IN_PROGRESS = "in_progress" - QUEUED = "queued" - SUPERSEDED = "superseded" - - - class azure.ai.projects.models.Metadata(_Model): - - - class azure.ai.projects.models.Microsoft365PermissionScopes(_Model): - resource_app_id: str - scopes: list[str] + class azure.ai.projects.models.LiveDecisionCompleted(_Model): + decision: DecisionResponse + type: Literal["completed"] @overload def __init__( self, *, - resource_app_id: str, - scopes: list[str] + decision: DecisionResponse ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.Microsoft365PublishDefaults(_Model): - agent_display_name: Optional[str] - agent_name: Optional[str] - app_publish_scope: Optional[Union[str, Microsoft365PublishScope]] - app_registration_client_id: Optional[str] - app_version: Optional[str] - bot_service_arm_id: Optional[str] - developer_name: Optional[str] - developer_website_url: Optional[str] - full_description: Optional[str] - privacy_url: Optional[str] - recommended_next_app_version: Optional[str] - short_description: Optional[str] - teams_app_id: Optional[str] - terms_of_use_url: Optional[str] - title_id: Optional[str] + class azure.ai.projects.models.LiveDecisionCustomToolCallOutputParam(LiveDecisionInputItemParam, discriminator='custom_tool_call_output'): + call_id: str + id: Optional[str] + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionInputItemParamType.CUSTOM_TOOL_CALL_OUTPUT] @overload def __init__( self, *, - agent_display_name: Optional[str] = ..., - agent_name: Optional[str] = ..., - app_publish_scope: Optional[Union[str, Microsoft365PublishScope]] = ..., - app_registration_client_id: Optional[str] = ..., - app_version: Optional[str] = ..., - bot_service_arm_id: Optional[str] = ..., - developer_name: Optional[str] = ..., - developer_website_url: Optional[str] = ..., - full_description: Optional[str] = ..., - privacy_url: Optional[str] = ..., - recommended_next_app_version: Optional[str] = ..., - short_description: Optional[str] = ..., - teams_app_id: Optional[str] = ..., - terms_of_use_url: Optional[str] = ..., - title_id: Optional[str] = ... + call_id: str, + id: Optional[str] = ..., + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]], + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.Microsoft365PublishResult(_Model): - teams_app_id: Optional[str] - title_id: Optional[str] + class azure.ai.projects.models.LiveDecisionCustomToolCallParam(LiveDecisionInputItemParam, discriminator='custom_tool_call'): + call_id: str + id: Optional[str] + input: str + name: str + namespace: Optional[str] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionInputItemParamType.CUSTOM_TOOL_CALL] @overload def __init__( self, *, - teams_app_id: Optional[str] = ..., - title_id: Optional[str] = ... + call_id: str, + id: Optional[str] = ..., + input: str, + name: str, + namespace: Optional[str] = ..., + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.Microsoft365PublishScope(str, Enum, metaclass=CaseInsensitiveEnumMeta): - PERSONAL = "Personal" - SHARED = "Shared" - TENANT = "Tenant" - - - class azure.ai.projects.models.MicrosoftCopilotBuiltInTool(str, Enum, metaclass=CaseInsensitiveEnumMeta): - FILESYSTEM_READ = "filesystem_read" - FILESYSTEM_WRITE = "filesystem_write" - SHELL = "shell" - SUBAGENTS = "subagents" - WEB = "web" - - - class azure.ai.projects.models.MicrosoftCopilotHarness(AgentHarness, discriminator='microsoft_copilot_preview'): - type: Literal["microsoft_copilot_preview"] + class azure.ai.projects.models.LiveDecisionFunctionCallOutputParam(LiveDecisionInputItemParam, discriminator='function_call_output'): + call_id: str + id: Optional[str] + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionInputItemParamType.FUNCTION_CALL_OUTPUT] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + call_id: str, + id: Optional[str] = ..., + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]], + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MicrosoftCopilotToolsetConfig(_Model): - enabled: Optional[bool] - name: Union[str, MicrosoftCopilotBuiltInTool] + class azure.ai.projects.models.LiveDecisionFunctionCallParam(LiveDecisionInputItemParam, discriminator='function_call'): + arguments: str + call_id: str + id: Optional[str] + name: str + namespace: Optional[str] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionInputItemParamType.FUNCTION_CALL] @overload def __init__( self, *, - enabled: Optional[bool] = ..., - name: Union[str, MicrosoftCopilotBuiltInTool] + arguments: str, + call_id: str, + id: Optional[str] = ..., + name: str, + namespace: Optional[str] = ..., + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MicrosoftCopilotToolsetDefaultConfig(_Model): - enabled: Optional[bool] + class azure.ai.projects.models.LiveDecisionInputImageParam(_Model): + detail: Optional[Union[str, LiveDetailEnum]] + image_url: str + type: Literal["input_image"] @overload def __init__( self, *, - enabled: Optional[bool] = ... + detail: Optional[Union[str, LiveDetailEnum]] = ..., + image_url: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MicrosoftCopilotToolsetPreview(Tool, discriminator='microsoft_copilot_toolset_preview'): - configs: Optional[list[MicrosoftCopilotToolsetConfig]] - default_config: Optional[MicrosoftCopilotToolsetDefaultConfig] - type: Literal[ToolType.MICROSOFT_COPILOT_TOOLSET_PREVIEW] + class azure.ai.projects.models.LiveDecisionInputItemParam(_Model): + type: str @overload def __init__( self, *, - configs: Optional[list[MicrosoftCopilotToolsetConfig]] = ..., - default_config: Optional[MicrosoftCopilotToolsetDefaultConfig] = ... + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MicrosoftFabricPreviewTool(Tool, discriminator='fabric_dataagent_preview'): - fabric_dataagent_preview: FabricDataAgentToolParameters - type: Literal[ToolType.FABRIC_DATAAGENT_PREVIEW] + class azure.ai.projects.models.LiveDecisionInputItemParamMessage(LiveDecisionInputItemParam, discriminator='message'): + type: Literal[LiveDecisionInputItemParamType.MESSAGE] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.LiveDecisionInputItemParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CUSTOM_TOOL_CALL = "custom_tool_call" + CUSTOM_TOOL_CALL_OUTPUT = "custom_tool_call_output" + FUNCTION_CALL = "function_call" + FUNCTION_CALL_OUTPUT = "function_call_output" + MESSAGE = "message" + + + class azure.ai.projects.models.LiveDecisionInputJsonParam(_Model): + data: Union[LiveDecisionJsonObject, list[LiveDecisionJsonObject]] + type: Literal["input_json"] @overload def __init__( self, *, - fabric_dataagent_preview: FabricDataAgentToolParameters + data: Union[LiveDecisionJsonObject, list[LiveDecisionJsonObject]] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MisalignmentErrorDetailsResource(_Model): - detailed_explanation: Optional[str] - error_type: Optional[Union[str, MisalignmentErrorType]] - steer: Optional[MisalignmentSteer] + class azure.ai.projects.models.LiveDecisionInputTextParam(_Model): + text: str + type: Literal["input_text"] @overload def __init__( self, *, - detailed_explanation: Optional[str] = ..., - error_type: Optional[Union[str, MisalignmentErrorType]] = ..., - steer: Optional[MisalignmentSteer] = ... + text: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MisalignmentErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - OTHER = "other" - POTENTIALLY_UNINTENDED_DATA_ACCESS = "potentially_unintended_data_access" - POTENTIALLY_UNINTENDED_DATA_TRANSFER = "potentially_unintended_data_transfer" - POTENTIALLY_UNINTENDED_DESTRUCTIVE_ACTIVITY = "potentially_unintended_destructive_activity" + class azure.ai.projects.models.LiveDecisionJsonObject(_Model): - class azure.ai.projects.models.MisalignmentSteer(_Model): - message: str + class azure.ai.projects.models.LiveDecisionPredicateQuestionParam(LiveDecisionQuestion, discriminator='predicate'): + instructions: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam, LiveDecisionInputJsonParam]]] + name: Optional[str] + type: Literal[LiveDecisionQuestionType.PREDICATE] @overload def __init__( self, *, - message: str + instructions: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam, LiveDecisionInputJsonParam]]], + name: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelCredentialRequest(_Model): - blob_uri: str + class azure.ai.projects.models.LiveDecisionQuestion(_Model): + type: str @overload def __init__( self, *, - blob_uri: str + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelDeployment(Deployment, discriminator='ModelDeployment'): - capabilities: dict[str, str] - connection_name: Optional[str] - model_name: str - model_publisher: str - model_version: str - name: str - sku: ModelDeploymentSku - type: Literal[DeploymentType.MODEL_DEPLOYMENT] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.LiveDecisionQuestionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CHOICE = "choice" + PREDICATE = "predicate" + SCORE = "score" - class azure.ai.projects.models.ModelDeploymentSku(_Model): - capacity: int - family: str - name: str - size: str - tier: str + class azure.ai.projects.models.LiveDecisionQuestionsInputParam(_Model): + questions: list[LiveDecisionQuestion] @overload def __init__( self, *, - capacity: int, - family: str, - name: str, - size: str, - tier: str + questions: list[LiveDecisionQuestion] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelPendingUploadRequest(_Model): - connection_name: Optional[str] - pending_upload_id: Optional[str] - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] + class azure.ai.projects.models.LiveDecisionScoreLevelParam(_Model): + description: Optional[str] + label: str @overload def __init__( self, *, - connection_name: Optional[str] = ..., - pending_upload_id: Optional[str] = ..., - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] + description: Optional[str] = ..., + label: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelPendingUploadResponse(_Model): - blob_reference: BlobReference - pending_upload_id: str - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] - version: Optional[str] + class azure.ai.projects.models.LiveDecisionScoreQuestionParam(LiveDecisionQuestion, discriminator='score'): + instructions: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam, LiveDecisionInputJsonParam]]] + levels: list[LiveDecisionScoreLevelParam] + name: Optional[str] + type: Literal[LiveDecisionQuestionType.SCORE] @overload def __init__( self, *, - blob_reference: BlobReference, - pending_upload_id: str, - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], - version: Optional[str] = ... + instructions: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam, LiveDecisionInputJsonParam]]], + levels: list[LiveDecisionScoreLevelParam], + name: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelSamplingConfigParam(TypedDict, total=False): - key "max_completion_tokens": int - key "seed": int - key "temperature": float - key "top_p": float - - - class azure.ai.projects.models.ModelSamplingParams(_Model): - max_completion_tokens: Optional[int] - seed: Optional[int] - temperature: Optional[float] - top_p: Optional[float] + class azure.ai.projects.models.LiveDecisionStoredCustomToolCallOutputParam(LiveDecisionStoredInputItemParam, discriminator='custom_tool_call_output'): + call_id: str + id: str + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionStoredInputItemParamType.CUSTOM_TOOL_CALL_OUTPUT] @overload def __init__( self, *, - max_completion_tokens: Optional[int] = ..., - seed: Optional[int] = ..., - temperature: Optional[float] = ..., - top_p: Optional[float] = ... + call_id: str, + id: str, + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]], + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelSourceData(_Model): - job_id: Optional[str] - source_type: Optional[Union[str, FoundryModelSourceType]] + class azure.ai.projects.models.LiveDecisionStoredCustomToolCallParam(LiveDecisionStoredInputItemParam, discriminator='custom_tool_call'): + call_id: str + id: str + input: str + name: str + namespace: Optional[str] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionStoredInputItemParamType.CUSTOM_TOOL_CALL] @overload def __init__( self, *, - job_id: Optional[str] = ..., - source_type: Optional[Union[str, FoundryModelSourceType]] = ... + call_id: str, + id: str, + input: str, + name: str, + namespace: Optional[str] = ..., + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ModelVersion(_Model): - artifact_profile: Optional[ArtifactProfile] - base_model: Optional[str] - blob_uri: str - description: Optional[str] - id: Optional[str] - lora_config: Optional[LoraConfig] - name: str - source: Optional[ModelSourceData] - tags: Optional[dict[str, str]] - version: str - warnings: Optional[list[FoundryModelWarning]] - weight_type: Optional[Union[str, FoundryModelWeightType]] + class azure.ai.projects.models.LiveDecisionStoredFunctionCallOutputParam(LiveDecisionStoredInputItemParam, discriminator='function_call_output'): + call_id: str + id: str + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionStoredInputItemParamType.FUNCTION_CALL_OUTPUT] @overload def __init__( self, *, - base_model: Optional[str] = ..., - blob_uri: str, - description: Optional[str] = ..., - lora_config: Optional[LoraConfig] = ..., - source: Optional[ModelSourceData] = ..., - tags: Optional[dict[str, str]] = ..., - weight_type: Optional[Union[str, FoundryModelWeightType]] = ... + call_id: str, + id: str, + output: Union[str, list[Union[LiveDecisionInputTextParam, LiveDecisionInputImageParam]]], + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.MonthlyRecurrenceSchedule(RecurrenceSchedule, discriminator='Monthly'): - days_of_month: list[int] - type: Literal[RecurrenceType.MONTHLY] + class azure.ai.projects.models.LiveDecisionStoredFunctionCallParam(LiveDecisionStoredInputItemParam, discriminator='function_call'): + arguments: str + call_id: str + id: str + name: str + namespace: Optional[str] + status: Optional[Union[str, LiveFunctionCallItemStatus]] + type: Literal[LiveDecisionStoredInputItemParamType.FUNCTION_CALL] @overload def __init__( self, *, - days_of_month: list[int] + arguments: str, + call_id: str, + id: str, + name: str, + namespace: Optional[str] = ..., + status: Optional[Union[str, LiveFunctionCallItemStatus]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.NamespaceToolParam(Tool, discriminator='namespace'): - description: str - name: str - tools: list[Union[FunctionToolParam, CustomToolParam]] - type: Literal[ToolType.NAMESPACE] + class azure.ai.projects.models.LiveDecisionStoredInputItemParam(_Model): + type: str @overload def __init__( self, *, - description: str, - name: str, - tools: list[Union[FunctionToolParam, CustomToolParam]] + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.NoAuthenticationCredentials(BaseCredentials, discriminator='None'): - type: Literal[CredentialType.NONE] + class azure.ai.projects.models.LiveDecisionStoredInputItemParamMessage(LiveDecisionStoredInputItemParam, discriminator='message'): + type: Literal[LiveDecisionStoredInputItemParamType.MESSAGE] @overload def __init__(self) -> None: ... @@ -9765,661 +10119,668 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OneTimeTrigger(Trigger, discriminator='OneTime'): - time_zone: Optional[str] - trigger_at: datetime - type: Literal[TriggerType.ONE_TIME] + class azure.ai.projects.models.LiveDecisionStoredInputItemParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CUSTOM_TOOL_CALL = "custom_tool_call" + CUSTOM_TOOL_CALL_OUTPUT = "custom_tool_call_output" + FUNCTION_CALL = "function_call" + FUNCTION_CALL_OUTPUT = "function_call_output" + MESSAGE = "message" + + + class azure.ai.projects.models.LiveDecisionTriggerInputParam(_Model): + decisions: LiveDecisionQuestionsInputParam + event_type: Literal["delta", "delta"] + type: Literal["decisions"] @overload def __init__( self, *, - time_zone: Optional[str] = ..., - trigger_at: datetime + decisions: LiveDecisionQuestionsInputParam, + event_type: Literal["delta", "delta"] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiAnonymousAuthDetails(OpenApiAuthDetails, discriminator='anonymous'): - type: Literal[OpenApiAuthType.ANONYMOUS] + class azure.ai.projects.models.LiveDecisionsDelegationUpdateParam(LiveSessionUpdateParamsDelegation, discriminator='decisions'): + acknowledgement_delay_ms: Optional[int] + decisions: Optional[LiveDecisionsSettingsUpdateParam] + type: Literal[LiveSessionUpdateParamsDelegationType.DECISIONS] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + acknowledgement_delay_ms: Optional[int] = ..., + decisions: Optional[LiveDecisionsSettingsUpdateParam] = ... + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiAuthDetails(_Model): - type: str + class azure.ai.projects.models.LiveDecisionsSettingsInputParam(_Model): + model: str + questions: list[LiveDecisionQuestion] @overload def __init__( self, *, - type: str + model: str, + questions: list[LiveDecisionQuestion] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiAuthType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ANONYMOUS = "anonymous" - MANAGED_IDENTITY = "managed_identity" - PROJECT_CONNECTION = "project_connection" - - - class azure.ai.projects.models.OpenApiFunctionDefinition(_Model): - auth: OpenApiAuthDetails - default_params: Optional[list[str]] - description: Optional[str] - functions: Optional[list[OpenApiFunctionDefinitionFunction]] - name: str - spec: dict[str, Any] + class azure.ai.projects.models.LiveDecisionsSettingsUpdateParam(_Model): + model: Optional[str] + questions: Optional[list[LiveDecisionQuestion]] @overload def __init__( self, *, - auth: OpenApiAuthDetails, - default_params: Optional[list[str]] = ..., - description: Optional[str] = ..., - name: str, - spec: dict[str, Any] + model: Optional[str] = ..., + questions: Optional[list[LiveDecisionQuestion]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiFunctionDefinitionFunction(_Model): - description: Optional[str] - name: str - parameters: dict[str, Any] + class azure.ai.projects.models.LiveDelegationReasoningInputParam(_Model): + effort: Optional[Union[str, LiveReasoningEffort]] + summary: Optional[Union[str, LiveReasoningSummary]] @overload def __init__( self, *, - description: Optional[str] = ..., - name: str, - parameters: dict[str, Any] + effort: Optional[Union[str, LiveReasoningEffort]] = ..., + summary: Optional[Union[str, LiveReasoningSummary]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiManagedAuthDetails(OpenApiAuthDetails, discriminator='managed_identity'): - security_scheme: OpenApiManagedSecurityScheme - type: Literal[OpenApiAuthType.MANAGED_IDENTITY] + class azure.ai.projects.models.LiveDelegationTextInputParam(_Model): + verbosity: Optional[Union[str, LiveTextVerbosity]] @overload def __init__( self, *, - security_scheme: OpenApiManagedSecurityScheme + verbosity: Optional[Union[str, LiveTextVerbosity]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiManagedSecurityScheme(_Model): - audience: str + class azure.ai.projects.models.LiveDetailEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + HIGH = "high" + LOW = "low" + ORIGINAL = "original" + + + class azure.ai.projects.models.LiveFileSearchToolInputParam(_Model): + type: Literal["file_search"] - @overload def __init__( self, - *, - audience: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.LiveFunctionCallItemStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COMPLETED = "completed" + INCOMPLETE = "incomplete" + IN_PROGRESS = "in_progress" - class azure.ai.projects.models.OpenApiProjectConnectionAuthDetails(OpenApiAuthDetails, discriminator='project_connection'): - security_scheme: OpenApiProjectConnectionSecurityScheme - type: Literal[OpenApiAuthType.PROJECT_CONNECTION] + + class azure.ai.projects.models.LiveFunctionToolChoiceParam(_Model): + name: str + type: Literal["function"] @overload def __init__( self, *, - security_scheme: OpenApiProjectConnectionSecurityScheme + name: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiProjectConnectionSecurityScheme(_Model): - project_connection_id: str + class azure.ai.projects.models.LiveFunctionToolInputParam(_Model): + description: Optional[str] + name: str + parameters: Optional[dict[str, Any]] + strict: Optional[bool] + type: Literal["function"] @overload def __init__( self, *, - project_connection_id: str + description: Optional[str] = ..., + name: str, + parameters: Optional[dict[str, Any]] = ..., + strict: Optional[bool] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiTool(Tool, discriminator='openapi'): - openapi: OpenApiFunctionDefinition - tool_configs: Optional[dict[str, ToolConfig]] - type: Literal[ToolType.OPENAPI] + class azure.ai.projects.models.LiveHostedShellContainerAutoParam(_Model): + file_ids: Optional[list[str]] + memory_limit: Optional[Union[str, LiveContainerMemoryLimit]] + network_policy: Optional[Union[LiveContainerNetworkPolicyDisabledParam, LiveHostedShellNetworkPolicyAllowlistParam]] + skills: Optional[list[Union[LiveSkillReferenceParam, LiveInlineSkillParam]]] + type: Literal["container_auto"] @overload def __init__( self, *, - openapi: OpenApiFunctionDefinition, - tool_configs: Optional[dict[str, ToolConfig]] = ... + file_ids: Optional[list[str]] = ..., + memory_limit: Optional[Union[str, LiveContainerMemoryLimit]] = ..., + network_policy: Optional[Union[LiveContainerNetworkPolicyDisabledParam, LiveHostedShellNetworkPolicyAllowlistParam]] = ..., + skills: Optional[list[Union[LiveSkillReferenceParam, LiveInlineSkillParam]]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OpenApiToolboxTool(ToolboxTool, discriminator='openapi'): - description: str - name: str - openapi: OpenApiFunctionDefinition - tool_configs: dict[str, ToolConfig] - type: Literal[ToolboxToolType.OPENAPI] + class azure.ai.projects.models.LiveHostedShellNetworkPolicyAllowlistParam(_Model): + allowed_domains: list[str] + type: Literal["allowlist"] @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ..., - openapi: OpenApiFunctionDefinition, - tool_configs: Optional[dict[str, ToolConfig]] = ... + allowed_domains: list[str] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OperationState(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CANCELED = "Canceled" - FAILED = "Failed" - NOT_STARTED = "NotStarted" - RUNNING = "Running" - SUCCEEDED = "Succeeded" - - - class azure.ai.projects.models.OptimizationContext(_Model): - type: str + class azure.ai.projects.models.LiveHostedShellToolInputParam(_Model): + environment: Optional[Union[LiveHostedShellContainerAutoParam, LiveContainerReferenceParam, LiveLocalEnvironmentParam]] + type: Literal["shell"] @overload def __init__( self, *, - type: str + environment: Optional[Union[LiveHostedShellContainerAutoParam, LiveContainerReferenceParam, LiveLocalEnvironmentParam]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.OptimizationContextType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - STEERING_PROMPT = "steering_prompt" + class azure.ai.projects.models.LiveImageGenerationToolInputParam(_Model): + type: Literal["image_generation"] + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... - class azure.ai.projects.models.OtlpTelemetryEndpoint(TelemetryEndpoint, discriminator='OTLP'): - auth: TelemetryEndpointAuth - data: Union[list[str, TelemetryDataKind]] - endpoint: str - kind: Literal[TelemetryEndpointKind.OTLP] - protocol: Union[str, TelemetryTransportProtocol] + + class azure.ai.projects.models.LiveInitialAssistantMessageItemParam(LiveInitialItem, discriminator='assistant'): + content: list[Union[LiveInitialTextContentPartParam, LiveInitialOutputTextContentPartParam]] + id: Optional[str] + role: Literal[LiveInitialItemType.ASSISTANT] + status: Optional[Union[str, LiveInitialMessageStatus]] + type: Optional[Literal["message"]] @overload def __init__( self, *, - auth: Optional[TelemetryEndpointAuth] = ..., - data: list[Union[str, TelemetryDataKind]], - endpoint: str, - protocol: Union[str, TelemetryTransportProtocol] + content: list[Union[LiveInitialTextContentPartParam, LiveInitialOutputTextContentPartParam]], + id: Optional[str] = ..., + status: Optional[Union[str, LiveInitialMessageStatus]] = ..., + type: Optional[Literal[message]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PSTNTelephonyTransferDestination(TelephonyTransferDestination, discriminator='pstn'): - kind: Literal[TelephonyTransferDestinationKind.PSTN] - value: str + class azure.ai.projects.models.LiveInitialDeveloperMessageItemParam(LiveInitialItem, discriminator='developer'): + content: list[LiveInitialInputTextContentPartParam] + id: Optional[str] + role: Literal[LiveInitialItemType.DEVELOPER] + status: Optional[Union[str, LiveInitialMessageStatus]] + type: Optional[Literal["message"]] @overload def __init__( self, *, - value: str + content: list[LiveInitialInputTextContentPartParam], + id: Optional[str] = ..., + status: Optional[Union[str, LiveInitialMessageStatus]] = ..., + type: Optional[Literal[message]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PageOrder(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ASC = "asc" - DESC = "desc" - - - class azure.ai.projects.models.PendingUploadRequest(_Model): - connection_name: Optional[str] - pending_upload_id: Optional[str] - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] + class azure.ai.projects.models.LiveInitialInputTextContentPartParam(_Model): + text: str + type: Optional[Literal["input_text"]] @overload def __init__( self, *, - connection_name: Optional[str] = ..., - pending_upload_id: Optional[str] = ..., - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] + text: str, + type: Optional[Literal[input_text]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PendingUploadResponse(_Model): - blob_reference: BlobReference - pending_upload_id: str - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] - version: Optional[str] + class azure.ai.projects.models.LiveInitialItem(_Model): + role: str @overload def __init__( self, *, - blob_reference: BlobReference, - pending_upload_id: str, - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], - version: Optional[str] = ... + role: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PendingUploadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - BLOB_REFERENCE = "BlobReference" - NONE = "None" - TEMPORARY_BLOB_REFERENCE = "TemporaryBlobReference" + class azure.ai.projects.models.LiveInitialItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ASSISTANT = "assistant" + DEVELOPER = "developer" + USER = "user" - class azure.ai.projects.models.PickPropertiesVoiceAgentAudioConfig(_Model): - output: Optional[VoiceAgentAudioOutputConfig] + class azure.ai.projects.models.LiveInitialMessageStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COMPLETED = "completed" + INCOMPLETE = "incomplete" + + + class azure.ai.projects.models.LiveInitialOutputTextContentPartParam(_Model): + text: str + type: Literal["output_text"] @overload def __init__( self, *, - output: Optional[VoiceAgentAudioOutputConfig] = ... + text: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ProceduralMemoryItem(MemoryItem, discriminator='procedural'): - content: str - kind: Literal[MemoryItemKind.PROCEDURAL] - memory_id: str - scope: str - updated_at: datetime + class azure.ai.projects.models.LiveInitialSessionAudioOutputParam(_Model): + voice: Optional[Union[str, Literal["alloy"], Literal["ash"], Literal["ballad"], Literal["beacon"], Literal["bossa"], Literal["brise"], Literal["cedar"], Literal["cinder"], Literal["coral"], Literal["delta"], Literal["echo"], Literal["flitz"], Literal["gleam"], Literal["harema"], Literal["juni"], Literal["marin"], Literal["meridian"], Literal["nira"], Literal["noeul"], Literal["nuri"], Literal["quartz"], Literal["ripple"], Literal["sage"], Literal["shida"], Literal["shimmer"], Literal["sillage"], Literal["stone"], Literal["tempo"], Literal["verse"], Literal["vesper"], Literal["willow"], LiveCustomVoiceParam]] @overload def __init__( self, *, - content: str, - memory_id: str, - scope: str, - updated_at: datetime + voice: Optional[Union[str, Literal[alloy], Literal[ash], Literal[ballad], Literal[beacon], Literal[bossa], Literal[brise], Literal[cedar], Literal[cinder], Literal[coral], Literal[delta], Literal[echo], Literal[flitz], Literal[gleam], Literal[harema], Literal[juni], Literal[marin], Literal[meridian], Literal[nira], Literal[noeul], Literal[nuri], Literal[quartz], Literal[ripple], Literal[sage], Literal[shida], Literal[shimmer], Literal[sillage], Literal[stone], Literal[tempo], Literal[verse], Literal[vesper], Literal[willow], LiveCustomVoiceParam]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ProgrammaticToolCallingParam(Tool, discriminator='programmatic_tool_calling'): - type: Literal[ToolType.PROGRAMMATIC_TOOL_CALLING] + class azure.ai.projects.models.LiveInitialSessionAudioParam(_Model): + format: Optional[LiveAudioFormat] + output: Optional[LiveInitialSessionAudioOutputParam] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + format: Optional[LiveAudioFormat] = ..., + output: Optional[LiveInitialSessionAudioOutputParam] = ... + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PromptAgentDefinition(AgentDefinition, discriminator='prompt'): - harness: Optional[AgentHarness] - instructions: Optional[str] - kind: Literal[AgentKind.PROMPT] - model: str - rai_config: RaiConfig - reasoning: Optional[Reasoning] - skills: Optional[list[SkillReference]] - structured_inputs: Optional[dict[str, StructuredInputDefinition]] - temperature: Optional[float] - text: Optional[PromptAgentDefinitionTextOptions] - tool_choice: Optional[Union[str, ToolChoiceParam]] - tools: Optional[list[Tool]] - top_p: Optional[float] + class azure.ai.projects.models.LiveInitialTextContentPartParam(_Model): + text: str + type: Optional[Literal["text"]] @overload def __init__( self, *, - harness: Optional[AgentHarness] = ..., - instructions: Optional[str] = ..., - model: str, - rai_config: Optional[RaiConfig] = ..., - reasoning: Optional[Reasoning] = ..., - skills: Optional[list[SkillReference]] = ..., - structured_inputs: Optional[dict[str, StructuredInputDefinition]] = ..., - temperature: Optional[float] = ..., - text: Optional[PromptAgentDefinitionTextOptions] = ..., - tool_choice: Optional[Union[str, ToolChoiceParam]] = ..., - tools: Optional[list[Tool]] = ..., - top_p: Optional[float] = ... + text: str, + type: Optional[Literal[text]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PromptAgentDefinitionTextOptions(_Model): - format: Optional[TextResponseFormat] + class azure.ai.projects.models.LiveInitialUserMessageItemParam(LiveInitialItem, discriminator='user'): + content: list[LiveInitialInputTextContentPartParam] + id: Optional[str] + role: Literal[LiveInitialItemType.USER] + status: Optional[Union[str, LiveInitialMessageStatus]] + type: Optional[Literal["message"]] @overload def __init__( self, *, - format: Optional[TextResponseFormat] = ... + content: list[LiveInitialInputTextContentPartParam], + id: Optional[str] = ..., + status: Optional[Union[str, LiveInitialMessageStatus]] = ..., + type: Optional[Literal[message]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PromptBasedEvaluatorDefinition(EvaluatorDefinition, discriminator='prompt'): - data_schema: dict[str, any] - init_parameters: dict[str, any] - metrics: dict[str, EvaluatorMetric] - prompt_text: str - type: Literal[EvaluatorDefinitionType.PROMPT] + class azure.ai.projects.models.LiveInlineSkillParam(_Model): + description: str + name: str + source: LiveInlineSkillSourceParam + type: Literal["inline"] @overload def __init__( self, *, - data_schema: Optional[dict[str, Any]] = ..., - init_parameters: Optional[dict[str, Any]] = ..., - metrics: Optional[dict[str, EvaluatorMetric]] = ..., - prompt_text: str + description: str, + name: str, + source: LiveInlineSkillSourceParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PromptDataGenerationJobSource(DataGenerationJobSource, discriminator='prompt'): - description: str - prompt: str - type: Literal[DataGenerationJobSourceType.PROMPT] + class azure.ai.projects.models.LiveInlineSkillSourceParam(_Model): + data: str + media_type: Literal["application/zip"] + type: Literal["base64"] @overload def __init__( self, *, - description: Optional[str] = ..., - prompt: str + data: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PromptEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator='prompt'): - description: Optional[str] - prompt: str - type: Literal[EvaluatorGenerationJobSourceType.PROMPT] + class azure.ai.projects.models.LiveInputAudioAppend(LiveServerEvent, discriminator='session.input_audio.append'): + audio: str + type: Literal[LiveServerEventType.SESSION_INPUT_AUDIO_APPEND] @overload def __init__( self, *, - description: Optional[str] = ..., - prompt: str + audio: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PromptOptimizationConfiguration(AgentOptimizationConfigurationBase, discriminator='prompt_optimization'): - context: Optional[list[OptimizationContext]] - type: Literal[AgentOptimizationConfigurationType.PROMPT_OPTIMIZATION] + class azure.ai.projects.models.LiveLiveError(_Model): + client_event_id: Optional[str] + code: str + message: str + param: Optional[str] + type: str @overload def __init__( self, *, - context: Optional[list[OptimizationContext]] = ... + client_event_id: Optional[str] = ..., + code: str, + message: str, + param: Optional[str] = ..., + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ProtocolConfiguration(_Model): - a2a: Optional[A2AProtocolConfiguration] - activity: Optional[ActivityProtocolConfiguration] - invocations: Optional[InvocationsProtocolConfiguration] - invocations_ws: Optional[InvocationsWsProtocolConfiguration] - mcp: Optional[McpProtocolConfiguration] - responses: Optional[ResponsesProtocolConfiguration] + class azure.ai.projects.models.LiveLocalEnvironmentParam(_Model): + skills: Optional[list[LiveLocalSkillParam]] + type: Literal["local"] @overload def __init__( self, *, - a2a: Optional[A2AProtocolConfiguration] = ..., - activity: Optional[ActivityProtocolConfiguration] = ..., - invocations: Optional[InvocationsProtocolConfiguration] = ..., - invocations_ws: Optional[InvocationsWsProtocolConfiguration] = ..., - mcp: Optional[McpProtocolConfiguration] = ..., - responses: Optional[ResponsesProtocolConfiguration] = ... + skills: Optional[list[LiveLocalSkillParam]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ProtocolVersionRecord(_Model): - protocol: Union[str, AgentEndpointProtocol] - version: str + class azure.ai.projects.models.LiveLocalSkillParam(_Model): + description: str + name: str + path: str @overload def __init__( self, *, - protocol: Union[str, AgentEndpointProtocol], - version: str + description: str, + name: str, + path: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.PublishApprovalStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - APPROVED = "approved" - NOT_PUBLISHED = "not_published" - NO_APPROVAL_NEEDED = "no_approval_needed" - PENDING = "pending" - REJECTED = "rejected" - - - class azure.ai.projects.models.RaiConfig(_Model): - invocations_moderation: Optional[RaiInvocationModeration] - rai_policy_name: str + class azure.ai.projects.models.LiveMCPToolChoiceParam(_Model): + name: Optional[str] + server_label: str + type: Literal["mcp"] @overload def __init__( self, *, - invocations_moderation: Optional[RaiInvocationModeration] = ..., - rai_policy_name: str + name: Optional[str] = ..., + server_label: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RaiInvocationContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - JSON = "json" - TEXT = "text" + class azure.ai.projects.models.LiveMCPToolInputParam(_Model): + type: Literal["mcp"] + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... - class azure.ai.projects.models.RaiInvocationMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): - BOTH = "both" - NON_STREAMING = "non_streaming" - STREAMING = "streaming" + class azure.ai.projects.models.LiveNamespaceToolInputParam(_Model): + type: Literal["namespace"] - class azure.ai.projects.models.RaiInvocationModeration(_Model): - input_content_type: Optional[Union[str, RaiInvocationContentType]] - input_paths: Optional[list[str]] - output_content_type: Optional[Union[str, RaiInvocationContentType]] - output_paths: Optional[list[str]] - response_mode: Union[str, RaiInvocationMode] - stream_selectors: Optional[list[RaiSseTextSelector]] + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + + class azure.ai.projects.models.LiveOutputAudioDelta(LiveServerEvent, discriminator='session.output_audio.delta'): + delta: str + end_ms: Optional[int] + start_ms: Optional[int] + type: Literal[LiveServerEventType.SESSION_OUTPUT_AUDIO_DELTA] @overload def __init__( self, *, - input_content_type: Optional[Union[str, RaiInvocationContentType]] = ..., - input_paths: Optional[list[str]] = ..., - output_content_type: Optional[Union[str, RaiInvocationContentType]] = ..., - output_paths: Optional[list[str]] = ..., - response_mode: Union[str, RaiInvocationMode], - stream_selectors: Optional[list[RaiSseTextSelector]] = ... + delta: str, + end_ms: Optional[int] = ..., + start_ms: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RaiSseTextSelector(_Model): - event_type: str - text_field: Optional[str] + class azure.ai.projects.models.LiveProgrammaticToolInputParam(_Model): + type: Literal["programmatic_tool_calling"] - @overload def __init__( self, - *, - event_type: str, - text_field: Optional[str] = ... + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.LiveReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + MEDIUM = "medium" + MINIMAL = "minimal" + NONE = "none" + XHIGH = "xhigh" - class azure.ai.projects.models.RankerVersionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + class azure.ai.projects.models.LiveReasoningSummary(str, Enum, metaclass=CaseInsensitiveEnumMeta): AUTO = "auto" - DEFAULT_2024_11_15 = "default-2024-11-15" + CONCISE = "concise" + DETAILED = "detailed" - class azure.ai.projects.models.RankingOptions(_Model): - hybrid_search: Optional[HybridSearchOptions] - ranker: Optional[Union[str, RankerVersionType]] - score_threshold: Optional[float] + class azure.ai.projects.models.LiveResponsesDelegationSettingsInputParam(_Model): + instructions: Optional[str] + max_output_tokens: Optional[int] + model: str + parallel_tool_calls: Optional[bool] + reasoning: Optional[LiveDelegationReasoningInputParam] + service_tier: Optional[Union[str, LiveResponsesServiceTier]] + text: Optional[LiveDelegationTextInputParam] + tool_choice: Optional[Union[str, LiveToolChoiceEnum, LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam]] + tools: Optional[list[Union[LiveFunctionToolInputParam, LiveWebSearchToolInputParam, LiveFileSearchToolInputParam, LiveCodeInterpreterToolInputParam, LiveHostedShellToolInputParam, LiveImageGenerationToolInputParam, LiveMCPToolInputParam, LiveCustomToolInputParam, LiveNamespaceToolInputParam, LiveToolSearchToolInputParam, LiveProgrammaticToolInputParam, LiveComputerToolInputParam, LiveApplyPatchToolInputParam]]] @overload def __init__( self, *, - hybrid_search: Optional[HybridSearchOptions] = ..., - ranker: Optional[Union[str, RankerVersionType]] = ..., - score_threshold: Optional[float] = ... + instructions: Optional[str] = ..., + max_output_tokens: Optional[int] = ..., + model: str, + parallel_tool_calls: Optional[bool] = ..., + reasoning: Optional[LiveDelegationReasoningInputParam] = ..., + service_tier: Optional[Union[str, LiveResponsesServiceTier]] = ..., + text: Optional[LiveDelegationTextInputParam] = ..., + tool_choice: Optional[Union[str, LiveToolChoiceEnum, LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam]] = ..., + tools: Optional[list[Union[LiveFunctionToolInputParam, LiveWebSearchToolInputParam, LiveFileSearchToolInputParam, LiveCodeInterpreterToolInputParam, LiveHostedShellToolInputParam, LiveImageGenerationToolInputParam, LiveMCPToolInputParam, LiveCustomToolInputParam, LiveNamespaceToolInputParam, LiveToolSearchToolInputParam, LiveProgrammaticToolInputParam, LiveComputerToolInputParam, LiveApplyPatchToolInputParam]]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeAudioFormats(_Model): - type: str + class azure.ai.projects.models.LiveResponsesDelegationSettingsUpdateInputParam(_Model): + instructions: Optional[str] + max_output_tokens: Optional[int] + model: Optional[str] + parallel_tool_calls: Optional[bool] + reasoning: Optional[LiveDelegationReasoningInputParam] + service_tier: Optional[Union[str, LiveResponsesServiceTier]] + text: Optional[LiveDelegationTextInputParam] + tool_choice: Optional[Union[str, LiveToolChoiceEnum, LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam]] + tools: Optional[list[Union[LiveFunctionToolInputParam, LiveWebSearchToolInputParam, LiveFileSearchToolInputParam, LiveCodeInterpreterToolInputParam, LiveHostedShellToolInputParam, LiveImageGenerationToolInputParam, LiveMCPToolInputParam, LiveCustomToolInputParam, LiveNamespaceToolInputParam, LiveToolSearchToolInputParam, LiveProgrammaticToolInputParam, LiveComputerToolInputParam, LiveApplyPatchToolInputParam]]] @overload def __init__( self, *, - type: str + instructions: Optional[str] = ..., + max_output_tokens: Optional[int] = ..., + model: Optional[str] = ..., + parallel_tool_calls: Optional[bool] = ..., + reasoning: Optional[LiveDelegationReasoningInputParam] = ..., + service_tier: Optional[Union[str, LiveResponsesServiceTier]] = ..., + text: Optional[LiveDelegationTextInputParam] = ..., + tool_choice: Optional[Union[str, LiveToolChoiceEnum, LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam]] = ..., + tools: Optional[list[Union[LiveFunctionToolInputParam, LiveWebSearchToolInputParam, LiveFileSearchToolInputParam, LiveCodeInterpreterToolInputParam, LiveHostedShellToolInputParam, LiveImageGenerationToolInputParam, LiveMCPToolInputParam, LiveCustomToolInputParam, LiveNamespaceToolInputParam, LiveToolSearchToolInputParam, LiveProgrammaticToolInputParam, LiveComputerToolInputParam, LiveApplyPatchToolInputParam]]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeAudioFormatsAudioPcm(RealtimeAudioFormats, discriminator='audio/pcm'): - rate: Optional[Literal[24000]] - type: Literal[RealtimeAudioFormatsType.AUDIO_PCM] + class azure.ai.projects.models.LiveResponsesDelegationUpdateParam(LiveSessionUpdateParamsDelegation, discriminator='responses'): + acknowledgement_delay_ms: Optional[int] + responses: Optional[LiveResponsesDelegationSettingsUpdateInputParam] + type: Literal[LiveSessionUpdateParamsDelegationType.RESPONSES] @overload def __init__( self, *, - rate: Optional[Literal[24000]] = ... + acknowledgement_delay_ms: Optional[int] = ..., + responses: Optional[LiveResponsesDelegationSettingsUpdateInputParam] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeAudioFormatsAudioPcma(RealtimeAudioFormats, discriminator='audio/pcma'): - type: Literal[RealtimeAudioFormatsType.AUDIO_PCMA] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.RealtimeAudioFormatsAudioPcmu(RealtimeAudioFormats, discriminator='audio/pcmu'): - type: Literal[RealtimeAudioFormatsType.AUDIO_PCMU] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.RealtimeAudioFormatsType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AUDIO_PCM = "audio/pcm" - AUDIO_PCMA = "audio/pcma" - AUDIO_PCMU = "audio/pcmu" + class azure.ai.projects.models.LiveResponsesServiceTier(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + DEFAULT = "default" + FAST_TIER_TEMP_PILOT = "fast_tier_temp_pilot" + FLEX = "flex" + PRIORITY = "priority" + ULTRAFAST = "ultrafast" - class azure.ai.projects.models.RealtimeClientEvent(_Model): + class azure.ai.projects.models.LiveServerEvent(_Model): type: str @overload @@ -10433,73 +10794,83 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventConversationItemCreate(RealtimeClientEvent, discriminator='conversation.item.create'): - event_id: Optional[str] - item: RealtimeConversationItem - previous_item_id: Optional[str] - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_CREATE] + class azure.ai.projects.models.LiveServerEventLiveCommentaryAppended(LiveServerEvent, discriminator='session.commentary.appended'): + client_event_id: Optional[str] + end_ms: int + event_id: str + start_ms: int + type: Literal[LiveServerEventType.SESSION_COMMENTARY_APPENDED] @overload def __init__( self, *, - event_id: Optional[str] = ..., - item: RealtimeConversationItem, - previous_item_id: Optional[str] = ... + client_event_id: Optional[str] = ..., + end_ms: int, + event_id: str, + start_ms: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventConversationItemDelete(RealtimeClientEvent, discriminator='conversation.item.delete'): - event_id: Optional[str] - item_id: str - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_DELETE] + class azure.ai.projects.models.LiveServerEventLiveDecisionEvent(LiveServerEvent, discriminator='decision.event'): + delegation_id: str + event: LiveDecisionCompleted + event_id: str + source_event_id: str + source_event_type: Literal["delta", "delta"] + trigger_id: str + type: Literal[LiveServerEventType.DECISION_EVENT] @overload def __init__( self, *, - event_id: Optional[str] = ..., - item_id: str + delegation_id: str, + event: LiveDecisionCompleted, + event_id: str, + source_event_id: str, + source_event_type: Literal["delta", "delta"], + trigger_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventConversationItemRetrieve(RealtimeClientEvent, discriminator='conversation.item.retrieve'): - event_id: Optional[str] - item_id: str - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_RETRIEVE] + class azure.ai.projects.models.LiveServerEventLiveDecisionItemCreated(LiveServerEvent, discriminator='decision.item.created'): + client_event_id: Optional[str] + event_id: str + item: LiveDecisionStoredInputItemParam + type: Literal[LiveServerEventType.DECISION_ITEM_CREATED] @overload def __init__( self, *, - event_id: Optional[str] = ..., - item_id: str + client_event_id: Optional[str] = ..., + event_id: str, + item: LiveDecisionStoredInputItemParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventConversationItemTruncate(RealtimeClientEvent, discriminator='conversation.item.truncate'): - audio_end_ms: int - content_index: int - event_id: Optional[str] + class azure.ai.projects.models.LiveServerEventLiveDecisionItemDeleted(LiveServerEvent, discriminator='decision.item.deleted'): + client_event_id: Optional[str] + event_id: str item_id: str - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_TRUNCATE] + type: Literal[LiveServerEventType.DECISION_ITEM_DELETED] @overload def __init__( self, *, - audio_end_ms: int, - content_index: int, - event_id: Optional[str] = ..., + client_event_id: Optional[str] = ..., + event_id: str, item_id: str ) -> None: ... @@ -10507,2650 +10878,2346 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventInputAudioBufferAppend(RealtimeClientEvent, discriminator='input_audio_buffer.append'): - audio: str - event_id: Optional[str] - type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_APPEND] + class azure.ai.projects.models.LiveServerEventLiveDelegationCreated(LiveServerEvent, discriminator='session.delegation.created'): + client_event_id: Optional[str] + delegation: VoiceAgentLiveDelegationItem + event_id: str + offset_ms: int + type: Literal[LiveServerEventType.SESSION_DELEGATION_CREATED] @overload def __init__( self, *, - audio: str, - event_id: Optional[str] = ... + client_event_id: Optional[str] = ..., + delegation: VoiceAgentLiveDelegationItem, + event_id: str, + offset_ms: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventInputAudioBufferClear(RealtimeClientEvent, discriminator='input_audio_buffer.clear'): - event_id: Optional[str] - type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_CLEAR] + class azure.ai.projects.models.LiveServerEventLiveErrorEvent(LiveServerEvent, discriminator='error'): + client_event_id: Optional[str] + error: LiveLiveError + event_id: str + type: Literal[LiveServerEventType.ERROR] @overload def __init__( self, *, - event_id: Optional[str] = ... + client_event_id: Optional[str] = ..., + error: LiveLiveError, + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventInputAudioBufferCommit(RealtimeClientEvent, discriminator='input_audio_buffer.commit'): - event_id: Optional[str] - type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_COMMIT] + class azure.ai.projects.models.LiveServerEventLiveInfoEvent(LiveServerEvent, discriminator='info'): + client_event_id: Optional[str] + code: str + event_id: str + message: str + type: Literal[LiveServerEventType.INFO] @overload def __init__( self, *, - event_id: Optional[str] = ... + client_event_id: Optional[str] = ..., + code: str, + event_id: str, + message: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventOutputAudioBufferClear(RealtimeClientEvent, discriminator='output_audio_buffer.clear'): - event_id: Optional[str] - type: Literal[RealtimeClientEventType.OUTPUT_AUDIO_BUFFER_CLEAR] + class azure.ai.projects.models.LiveServerEventLiveInputAudioMuted(LiveServerEvent, discriminator='session.input_audio.muted'): + client_event_id: Optional[str] + event_id: str + type: Literal[LiveServerEventType.SESSION_INPUT_AUDIO_MUTED] @overload def __init__( self, *, - event_id: Optional[str] = ... + client_event_id: Optional[str] = ..., + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventResponseCancel(RealtimeClientEvent, discriminator='response.cancel'): - event_id: Optional[str] - response_id: Optional[str] - type: Literal[RealtimeClientEventType.RESPONSE_CANCEL] + class azure.ai.projects.models.LiveServerEventLiveInputAudioUnmuted(LiveServerEvent, discriminator='session.input_audio.unmuted'): + client_event_id: Optional[str] + event_id: str + type: Literal[LiveServerEventType.SESSION_INPUT_AUDIO_UNMUTED] @overload def __init__( self, *, - event_id: Optional[str] = ..., - response_id: Optional[str] = ... + client_event_id: Optional[str] = ..., + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventResponseCreate(RealtimeClientEvent, discriminator='response.create'): - event_id: Optional[str] - response: Optional[VoiceAgentResponseCreateParams] - type: Literal[RealtimeClientEventType.RESPONSE_CREATE] + class azure.ai.projects.models.LiveServerEventLiveInputTranscriptDelta(LiveServerEvent, discriminator='session.input_transcript.delta'): + client_event_id: Optional[str] + delta: str + end_ms: int + event_id: str + start_ms: int + type: Literal[LiveServerEventType.SESSION_INPUT_TRANSCRIPT_DELTA] @overload def __init__( self, *, - event_id: Optional[str] = ..., - response: Optional[VoiceAgentResponseCreateParams] = ... + client_event_id: Optional[str] = ..., + delta: str, + end_ms: int, + event_id: str, + start_ms: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeClientEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CONVERSATION_ITEM_CREATE = "conversation.item.create" - CONVERSATION_ITEM_DELETE = "conversation.item.delete" - CONVERSATION_ITEM_RETRIEVE = "conversation.item.retrieve" - CONVERSATION_ITEM_TRUNCATE = "conversation.item.truncate" - INPUT_AUDIO_BUFFER_APPEND = "input_audio_buffer.append" - INPUT_AUDIO_BUFFER_CLEAR = "input_audio_buffer.clear" - INPUT_AUDIO_BUFFER_COMMIT = "input_audio_buffer.commit" - OUTPUT_AUDIO_BUFFER_CLEAR = "output_audio_buffer.clear" - RESPONSE_CANCEL = "response.cancel" - RESPONSE_CREATE = "response.create" - RTC_CALL_SDP_CREATE = "rtc.call.sdp.create" - SESSION_AVATAR_CONNECT = "session.avatar.connect" - SESSION_UPDATE = "session.update" - - - class azure.ai.projects.models.RealtimeConversationItem(_Model): - type: str + class azure.ai.projects.models.LiveServerEventLiveInstructionsAppended(LiveServerEvent, discriminator='session.instructions.appended'): + client_event_id: Optional[str] + end_ms: int + event_id: str + start_ms: int + type: Literal[LiveServerEventType.SESSION_INSTRUCTIONS_APPENDED] @overload def __init__( self, *, - type: str + client_event_id: Optional[str] = ..., + end_ms: int, + event_id: str, + start_ms: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemFunctionCall(RealtimeConversationItem, discriminator='function_call'): - arguments: str - call_id: Optional[str] - created_at: Optional[datetime] - id: Optional[str] - name: str - object: Optional[Literal["item"]] - response_id: Optional[str] - status: Optional[Literal["completed", "incomplete", "in_progress"]] - type: Literal[RealtimeConversationItemType.FUNCTION_CALL] + class azure.ai.projects.models.LiveServerEventLiveOutputAudioFixturePlayed(LiveServerEvent, discriminator='session.output_audio.fixture.played'): + client_event_id: Optional[str] + event_id: str + type: Literal[LiveServerEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED] @overload def __init__( self, *, - arguments: str, - call_id: Optional[str] = ..., - id: Optional[str] = ..., - name: str, - object: Optional[Literal[item]] = ..., - status: Optional[Literal[completed, incomplete, in_progress]] = ... + client_event_id: Optional[str] = ..., + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemFunctionCallOutput(RealtimeConversationItem, discriminator='function_call_output'): - call_id: str - created_at: Optional[datetime] - id: Optional[str] - name: Optional[str] - object: Optional[Literal["item"]] - output: str - response_id: Optional[str] - status: Optional[Literal["completed", "incomplete", "in_progress"]] - type: Literal[RealtimeConversationItemType.FUNCTION_CALL_OUTPUT] + class azure.ai.projects.models.LiveServerEventLiveOutputAudioFixturePlaying(LiveServerEvent, discriminator='session.output_audio.fixture.playing'): + client_event_id: Optional[str] + event_id: str + type: Literal[LiveServerEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING] @overload def __init__( self, *, - call_id: str, - id: Optional[str] = ..., - name: Optional[str] = ..., - object: Optional[Literal[item]] = ..., - output: str, - status: Optional[Literal[completed, incomplete, in_progress]] = ... + client_event_id: Optional[str] = ..., + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessage(RealtimeConversationItem, discriminator='message'): - role: str - type: Literal[RealtimeConversationItemType.MESSAGE] + class azure.ai.projects.models.LiveServerEventLiveOutputTranscriptDelta(LiveServerEvent, discriminator='session.output_transcript.delta'): + client_event_id: Optional[str] + delta: str + end_ms: int + event_id: str + start_ms: int + type: Literal[LiveServerEventType.SESSION_OUTPUT_TRANSCRIPT_DELTA] @overload def __init__( self, *, - role: str + client_event_id: Optional[str] = ..., + delta: str, + end_ms: int, + event_id: str, + start_ms: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessageAssistant(RealtimeConversationItemMessage, discriminator='assistant'): - content: list[RealtimeConversationItemMessageAssistantContent] - created_at: Optional[datetime] - id: Optional[str] - object: Optional[Literal["item"]] - response_id: Optional[str] - role: Literal[RealtimeConversationItemMessageType.ASSISTANT] - status: Optional[Literal["completed", "incomplete", "in_progress"]] - type: Union[str, azure.ai.projects.models.MESSAGE] + class azure.ai.projects.models.LiveServerEventLiveResponseEvent(LiveServerEvent, discriminator='response.event'): + client_event_id: Optional[str] + delegation_id: Optional[str] + event: dict[str, Any] + event_id: str + type: Literal[LiveServerEventType.RESPONSE_EVENT] @overload def __init__( self, *, - content: list[RealtimeConversationItemMessageAssistantContent], - id: Optional[str] = ..., - object: Optional[Literal[item]] = ..., - status: Optional[Literal[completed, incomplete, in_progress]] = ..., - type: Literal[RealtimeConversationItemType.MESSAGE] + client_event_id: Optional[str] = ..., + delegation_id: Optional[str] = ..., + event: dict[str, Any], + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessageAssistantContent(_Model): - audio: Optional[str] - text: Optional[str] - transcript: Optional[str] - type: Optional[Literal["output_text", "output_audio"]] + class azure.ai.projects.models.LiveServerEventLiveSessionClosed(LiveServerEvent, discriminator='session.closed'): + client_event_id: Optional[str] + event_id: str + reason: Literal["close_requested", "expired", "content", "remote_hangup", "connection_lost"] + session: VoiceAgentLiveSessionResource + type: Literal[LiveServerEventType.SESSION_CLOSED] + usage: LiveSessionUsage @overload def __init__( self, *, - audio: Optional[str] = ..., - text: Optional[str] = ..., - transcript: Optional[str] = ..., - type: Optional[Literal[output_text, output_audio]] = ... + client_event_id: Optional[str] = ..., + event_id: str, + reason: Literal["close_requested", "expired", "content", "remote_hangup", "connection_lost"], + session: VoiceAgentLiveSessionResource, + usage: LiveSessionUsage ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessageSystem(RealtimeConversationItemMessage, discriminator='system'): - content: list[RealtimeConversationItemMessageSystemContent] - created_at: Optional[datetime] - id: Optional[str] - object: Optional[Literal["item"]] - response_id: Optional[str] - role: Literal[RealtimeConversationItemMessageType.SYSTEM] - status: Optional[Literal["completed", "incomplete", "in_progress"]] - type: Union[str, azure.ai.projects.models.MESSAGE] + class azure.ai.projects.models.LiveServerEventLiveSessionStarted(LiveServerEvent, discriminator='session.started'): + client_event_id: Optional[str] + conversation_id: Optional[str] + event_id: str + session: VoiceAgentLiveSessionResource + type: Literal[LiveServerEventType.SESSION_STARTED] @overload def __init__( self, *, - content: list[RealtimeConversationItemMessageSystemContent], - id: Optional[str] = ..., - object: Optional[Literal[item]] = ..., - status: Optional[Literal[completed, incomplete, in_progress]] = ..., - type: Literal[RealtimeConversationItemType.MESSAGE] + client_event_id: Optional[str] = ..., + conversation_id: Optional[str] = ..., + event_id: str, + session: VoiceAgentLiveSessionResource ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessageSystemContent(_Model): - text: Optional[str] - type: Optional[Literal["input_text"]] + class azure.ai.projects.models.LiveServerEventLiveSessionUpdated(LiveServerEvent, discriminator='session.updated'): + client_event_id: Optional[str] + event_id: str + session: VoiceAgentLiveSessionResource + type: Literal[LiveServerEventType.SESSION_UPDATED] @overload def __init__( self, *, - text: Optional[str] = ..., - type: Optional[Literal[input_text]] = ... + client_event_id: Optional[str] = ..., + event_id: str, + session: VoiceAgentLiveSessionResource ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessageType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ASSISTANT = "assistant" - SYSTEM = "system" - USER = "user" - - - class azure.ai.projects.models.RealtimeConversationItemMessageUser(RealtimeConversationItemMessage, discriminator='user'): - content: list[RealtimeConversationItemMessageUserContent] - created_at: Optional[datetime] - id: Optional[str] - object: Optional[Literal["item"]] - response_id: Optional[str] - role: Literal[RealtimeConversationItemMessageType.USER] - status: Optional[Literal["completed", "incomplete", "in_progress"]] - type: Union[str, azure.ai.projects.models.MESSAGE] + class azure.ai.projects.models.LiveServerEventLiveSessionUsageUpdated(LiveServerEvent, discriminator='session.usage.updated'): + client_event_id: Optional[str] + context_window: Optional[LiveContextWindowUsage] + event_id: str + type: Literal[LiveServerEventType.SESSION_USAGE_UPDATED] + usage: LiveSessionUsage @overload def __init__( self, *, - content: list[RealtimeConversationItemMessageUserContent], - id: Optional[str] = ..., - object: Optional[Literal[item]] = ..., - status: Optional[Literal[completed, incomplete, in_progress]] = ..., - type: Literal[RealtimeConversationItemType.MESSAGE] + client_event_id: Optional[str] = ..., + context_window: Optional[LiveContextWindowUsage] = ..., + event_id: str, + usage: LiveSessionUsage ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemMessageUserContent(_Model): - audio: Optional[str] - detail: Optional[Literal["auto", "low", "high"]] - image_url: Optional[str] - text: Optional[str] - transcript: Optional[str] - type: Optional[Literal["input_text", "input_audio", "input_image"]] + class azure.ai.projects.models.LiveServerEventLiveThinkingAppended(LiveServerEvent, discriminator='session.thinking.appended'): + client_event_id: Optional[str] + end_ms: int + event_id: str + start_ms: int + type: Literal[LiveServerEventType.SESSION_THINKING_APPENDED] @overload def __init__( self, *, - audio: Optional[str] = ..., - detail: Optional[Literal[auto, low, high]] = ..., - image_url: Optional[str] = ..., - text: Optional[str] = ..., - transcript: Optional[str] = ..., - type: Optional[Literal[input_text, input_audio, input_image]] = ... + client_event_id: Optional[str] = ..., + end_ms: int, + event_id: str, + start_ms: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeConversationItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - FUNCTION_CALL = "function_call" - FUNCTION_CALL_OUTPUT = "function_call_output" - MCP_APPROVAL_REQUEST = "mcp_approval_request" - MCP_APPROVAL_RESPONSE = "mcp_approval_response" - MCP_CALL = "mcp_call" - MCP_LIST_TOOLS = "mcp_list_tools" - MESSAGE = "message" - - - class azure.ai.projects.models.RealtimeFunctionTool(_Model): - description: Optional[str] - name: Optional[str] - parameters: Optional[RealtimeFunctionToolParameters] - type: Optional[Literal["function"]] + class azure.ai.projects.models.LiveServerEventLiveTransportAnswered(LiveServerEvent, discriminator='transport.answered'): + event_id: str + session_id: str + type: Literal[LiveServerEventType.TRANSPORT_ANSWERED] @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ..., - parameters: Optional[RealtimeFunctionToolParameters] = ..., - type: Optional[Literal[function]] = ... + event_id: str, + session_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeFunctionToolParameters(_Model): - - - class azure.ai.projects.models.RealtimeMCPApprovalRequest(RealtimeConversationItem, discriminator='mcp_approval_request'): - arguments: str - created_at: Optional[datetime] - id: str - name: str - response_id: Optional[str] - server_label: str - type: Literal[RealtimeConversationItemType.MCP_APPROVAL_REQUEST] + class azure.ai.projects.models.LiveServerEventLiveTransportDtmfReceived(LiveServerEvent, discriminator='transport.dtmf.received'): + event: str + event_id: str + type: Literal[LiveServerEventType.TRANSPORT_DTMF_RECEIVED] @overload def __init__( self, *, - arguments: str, - id: str, - name: str, - server_label: str + event: str, + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPApprovalResponse(RealtimeConversationItem, discriminator='mcp_approval_response'): - approval_request_id: str - approve: bool - created_at: Optional[datetime] - id: str - reason: Optional[str] - response_id: Optional[str] - type: Literal[RealtimeConversationItemType.MCP_APPROVAL_RESPONSE] + class azure.ai.projects.models.LiveServerEventLiveTransportDtmfSent(LiveServerEvent, discriminator='transport.dtmf.sent'): + client_event_id: Optional[str] + event: str + event_id: str + type: Literal[LiveServerEventType.TRANSPORT_DTMF_SENT] @overload def __init__( self, *, - approval_request_id: str, - approve: bool, - id: str, - reason: Optional[str] = ... + client_event_id: Optional[str] = ..., + event: str, + event_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPError(_Model): - type: str + class azure.ai.projects.models.LiveServerEventLiveTransportFailed(LiveServerEvent, discriminator='transport.failed'): + error: LiveTransportCallError + event_id: str + session_id: str + type: Literal[LiveServerEventType.TRANSPORT_FAILED] @overload def __init__( self, *, - type: str + error: LiveTransportCallError, + event_id: str, + session_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPHTTPError(RealtimeMCPError, discriminator='http_error'): - code: int - message: str - type: Literal[RealtimeMcpErrorType.HTTP_ERROR] + class azure.ai.projects.models.LiveServerEventLiveTransportRinging(LiveServerEvent, discriminator='transport.ringing'): + event_id: str + session_id: str + type: Literal[LiveServerEventType.TRANSPORT_RINGING] @overload def __init__( self, *, - code: int, - message: str + event_id: str, + session_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPListTools(RealtimeConversationItem, discriminator='mcp_list_tools'): - created_at: Optional[datetime] - id: Optional[str] - response_id: Optional[str] - server_label: str - tools: list[MCPListToolsTool] - type: Literal[RealtimeConversationItemType.MCP_LIST_TOOLS] + class azure.ai.projects.models.LiveServerEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DECISION_EVENT = "decision.event" + DECISION_ITEM_CREATED = "decision.item.created" + DECISION_ITEM_DELETED = "decision.item.deleted" + ERROR = "error" + INFO = "info" + RESPONSE_EVENT = "response.event" + SESSION_CLOSED = "session.closed" + SESSION_COMMENTARY_APPENDED = "session.commentary.appended" + SESSION_DELEGATION_CREATED = "session.delegation.created" + SESSION_INPUT_AUDIO_APPEND = "session.input_audio.append" + SESSION_INPUT_AUDIO_MUTED = "session.input_audio.muted" + SESSION_INPUT_AUDIO_UNMUTED = "session.input_audio.unmuted" + SESSION_INPUT_TRANSCRIPT_DELTA = "session.input_transcript.delta" + SESSION_INSTRUCTIONS_APPENDED = "session.instructions.appended" + SESSION_OUTPUT_AUDIO_DELTA = "session.output_audio.delta" + SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED = "session.output_audio.fixture.played" + SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING = "session.output_audio.fixture.playing" + SESSION_OUTPUT_TRANSCRIPT_DELTA = "session.output_transcript.delta" + SESSION_STARTED = "session.started" + SESSION_THINKING_APPENDED = "session.thinking.appended" + SESSION_UPDATED = "session.updated" + SESSION_USAGE_UPDATED = "session.usage.updated" + TRANSPORT_ANSWERED = "transport.answered" + TRANSPORT_DTMF_RECEIVED = "transport.dtmf.received" + TRANSPORT_DTMF_SENT = "transport.dtmf.sent" + TRANSPORT_FAILED = "transport.failed" + TRANSPORT_RINGING = "transport.ringing" + + + class azure.ai.projects.models.LiveSessionAudioFormatPCMAParam(LiveAudioFormat, discriminator='audio/pcma'): + rate: int + type: Literal[LiveAudioFormatType.AUDIO_PCMA] @overload def __init__( self, *, - id: Optional[str] = ..., - server_label: str, - tools: list[MCPListToolsTool] + rate: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPProtocolError(RealtimeMCPError, discriminator='protocol_error'): - code: int - message: str - type: Literal[RealtimeMcpErrorType.PROTOCOL_ERROR] + class azure.ai.projects.models.LiveSessionAudioFormatPCMParam(LiveAudioFormat, discriminator='audio/pcm'): + rate: Literal[16000, 24000] + type: Literal[LiveAudioFormatType.AUDIO_PCM] @overload def __init__( self, *, - code: int, - message: str + rate: Literal[16000, 24000] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPToolCall(RealtimeConversationItem, discriminator='mcp_call'): - approval_request_id: Optional[str] - arguments: str - created_at: Optional[datetime] - error: Optional[RealtimeMCPError] - id: str - name: str - output: Optional[str] - response_id: Optional[str] - server_label: str - type: Literal[RealtimeConversationItemType.MCP_CALL] + class azure.ai.projects.models.LiveSessionAudioFormatPCMUParam(LiveAudioFormat, discriminator='audio/pcmu'): + rate: int + type: Literal[LiveAudioFormatType.AUDIO_PCMU] @overload def __init__( self, *, - approval_request_id: Optional[str] = ..., - arguments: str, - error: Optional[RealtimeMCPError] = ..., - id: str, - name: str, - output: Optional[str] = ..., - server_label: str + rate: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMCPToolExecutionError(RealtimeMCPError, discriminator='tool_execution_error'): - message: str - type: Literal[RealtimeMcpErrorType.TOOL_EXECUTION_ERROR] + class azure.ai.projects.models.LiveSessionCreateParams(_Model): + audio: Optional[LiveInitialSessionAudioParam] + client: Optional[LiveClientConfigParam] + delegation: Optional[LiveSessionCreateParamsDelegation] + input: Optional[list[LiveInitialItem]] + instructions: Optional[str] + model: Union[str, ModelIdsLive] + store: Optional[bool] + triggers: Optional[list[LiveDecisionTriggerInputParam]] @overload def __init__( self, *, - message: str + audio: Optional[LiveInitialSessionAudioParam] = ..., + client: Optional[LiveClientConfigParam] = ..., + delegation: Optional[LiveSessionCreateParamsDelegation] = ..., + input: Optional[list[LiveInitialItem]] = ..., + instructions: Optional[str] = ..., + model: Union[str, ModelIdsLive], + store: Optional[bool] = ..., + triggers: Optional[list[LiveDecisionTriggerInputParam]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeMcpErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - HTTP_ERROR = "http_error" - PROTOCOL_ERROR = "protocol_error" - TOOL_EXECUTION_ERROR = "tool_execution_error" - - - class azure.ai.projects.models.RealtimeReasoning(_Model): - effort: Optional[Union[str, RealtimeReasoningEffort]] + class azure.ai.projects.models.LiveSessionCreateParamsDelegation(_Model): + type: str @overload def __init__( self, *, - effort: Optional[Union[str, RealtimeReasoningEffort]] = ... + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): - HIGH = "high" - LOW = "low" - MEDIUM = "medium" - MINIMAL = "minimal" - XHIGH = "xhigh" - - - class azure.ai.projects.models.RealtimeResponseStatusDetails(_Model): - error: Optional[RealtimeResponseStatusDetailsError] - reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] - type: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] + class azure.ai.projects.models.LiveSessionCreateParamsDelegationLiveClientDelegationParam(LiveSessionCreateParamsDelegation, discriminator='client'): + acknowledgement_delay_ms: Optional[int] + type: Literal[LiveSessionCreateParamsDelegationType.CLIENT] @overload def __init__( self, *, - error: Optional[RealtimeResponseStatusDetailsError] = ..., - reason: Optional[Literal[turn_detected, client_cancelled, max_output_tokens, content_filter]] = ..., - type: Optional[Literal[completed, cancelled, failed, incomplete]] = ... + acknowledgement_delay_ms: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeResponseStatusDetailsError(_Model): - code: Optional[str] - type: Optional[str] + class azure.ai.projects.models.LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam(LiveSessionCreateParamsDelegation, discriminator='decisions'): + acknowledgement_delay_ms: Optional[int] + decisions: LiveDecisionsSettingsInputParam + type: Literal[LiveSessionCreateParamsDelegationType.DECISIONS] @overload def __init__( self, *, - code: Optional[str] = ..., - type: Optional[str] = ... + acknowledgement_delay_ms: Optional[int] = ..., + decisions: LiveDecisionsSettingsInputParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeResponseUsage(_Model): - input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] - input_tokens: Optional[int] - output_token_details: Optional[RealtimeResponseUsageOutputTokenDetails] - output_tokens: Optional[int] - total_tokens: Optional[int] + class azure.ai.projects.models.LiveSessionCreateParamsDelegationLiveResponsesDelegationParam(LiveSessionCreateParamsDelegation, discriminator='responses'): + acknowledgement_delay_ms: Optional[int] + responses: LiveResponsesDelegationSettingsInputParam + type: Literal[LiveSessionCreateParamsDelegationType.RESPONSES] @overload def __init__( self, *, - input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] = ..., - input_tokens: Optional[int] = ..., - output_token_details: Optional[RealtimeResponseUsageOutputTokenDetails] = ..., - output_tokens: Optional[int] = ..., - total_tokens: Optional[int] = ... + acknowledgement_delay_ms: Optional[int] = ..., + responses: LiveResponsesDelegationSettingsInputParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeResponseUsageInputTokenDetails(_Model): - audio_tokens: Optional[int] - cached_tokens: Optional[int] - cached_tokens_details: Optional[RealtimeResponseUsageInputTokenDetailsCachedTokensDetails] - image_tokens: Optional[int] - text_tokens: Optional[int] + class azure.ai.projects.models.LiveSessionCreateParamsDelegationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CLIENT = "client" + DECISIONS = "decisions" + RESPONSES = "responses" + + + class azure.ai.projects.models.LiveSessionStartEvent(LiveClientEvent, discriminator='session.start'): + event_id: Optional[str] + session: LiveSessionCreateParams + type: Literal[LiveClientEventType.SESSION_START] @overload def __init__( self, *, - audio_tokens: Optional[int] = ..., - cached_tokens: Optional[int] = ..., - cached_tokens_details: Optional[RealtimeResponseUsageInputTokenDetailsCachedTokensDetails] = ..., - image_tokens: Optional[int] = ..., - text_tokens: Optional[int] = ... + event_id: Optional[str] = ..., + session: LiveSessionCreateParams ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails(_Model): - audio_tokens: Optional[int] - image_tokens: Optional[int] - text_tokens: Optional[int] + class azure.ai.projects.models.LiveSessionUpdateParams(_Model): + delegation: Optional[LiveSessionUpdateParamsDelegation] + triggers: Optional[list[LiveDecisionTriggerInputParam]] @overload def __init__( self, *, - audio_tokens: Optional[int] = ..., - image_tokens: Optional[int] = ..., - text_tokens: Optional[int] = ... + delegation: Optional[LiveSessionUpdateParamsDelegation] = ..., + triggers: Optional[list[LiveDecisionTriggerInputParam]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeResponseUsageOutputTokenDetails(_Model): - audio_tokens: Optional[int] - text_tokens: Optional[int] + class azure.ai.projects.models.LiveSessionUpdateParamsDelegation(_Model): + type: str @overload def __init__( self, *, - audio_tokens: Optional[int] = ..., - text_tokens: Optional[int] = ... + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEvent(_Model): - type: str + class azure.ai.projects.models.LiveSessionUpdateParamsDelegationLiveClientDelegationParam(LiveSessionUpdateParamsDelegation, discriminator='client'): + acknowledgement_delay_ms: Optional[int] + type: Literal[LiveSessionUpdateParamsDelegationType.CLIENT] @overload def __init__( self, *, - type: str + acknowledgement_delay_ms: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventConversationItemAdded(RealtimeServerEvent, discriminator='conversation.item.added'): - event_id: str - item: RealtimeConversationItem - previous_item_id: Optional[str] - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_ADDED] + class azure.ai.projects.models.LiveSessionUpdateParamsDelegationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CLIENT = "client" + DECISIONS = "decisions" + RESPONSES = "responses" + + + class azure.ai.projects.models.LiveSessionUsage(_Model): + seconds: float @overload def __init__( self, *, - event_id: str, - item: RealtimeConversationItem, - previous_item_id: Optional[str] = ... + seconds: float ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventConversationItemCreated(RealtimeServerEvent, discriminator='conversation.item.created'): - event_id: str - item: RealtimeConversationItem - previous_item_id: Optional[str] - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_CREATED] + class azure.ai.projects.models.LiveSkillReferenceParam(_Model): + skill_id: str + type: Literal["skill_reference"] + version: Optional[str] @overload def __init__( self, *, - event_id: str, - item: RealtimeConversationItem, - previous_item_id: Optional[str] = ... + skill_id: str, + version: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventConversationItemDeleted(RealtimeServerEvent, discriminator='conversation.item.deleted'): - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DELETED] + class azure.ai.projects.models.LiveSpecificApplyPatchParam(_Model): + type: Literal["apply_patch"] - @overload def __init__( self, - *, - event_id: str, - item_id: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventConversationItemDone(RealtimeServerEvent, discriminator='conversation.item.done'): - event_id: str - item: RealtimeConversationItem - previous_item_id: Optional[str] - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DONE] + class azure.ai.projects.models.LiveSpecificCodeInterpreterParam(_Model): + type: Literal["code_interpreter"] - @overload def __init__( self, - *, - event_id: str, - item: RealtimeConversationItem, - previous_item_id: Optional[str] = ... + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionCompleted(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.completed'): - content_index: int - event_id: str - item_id: str - languages: Optional[list[TranscriptionLanguage]] - logprobs: Optional[list[LogProbProperties]] - phrases: Optional[list[VoiceAgentTranscriptionPhrase]] - transcript: str - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED] - usage: Union[TranscriptTextUsageTokens, TranscriptTextUsageDuration] + class azure.ai.projects.models.LiveSpecificComputerParam(_Model): + type: Literal["computer"] - @overload def __init__( self, - *, - content_index: int, - event_id: str, - item_id: str, - languages: Optional[list[TranscriptionLanguage]] = ..., - logprobs: Optional[list[LogProbProperties]] = ..., - phrases: Optional[list[VoiceAgentTranscriptionPhrase]] = ..., - transcript: str, - usage: Union[TranscriptTextUsageTokens, TranscriptTextUsageDuration] + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionDelta(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.delta'): - content_index: Optional[int] - delta: Optional[str] - event_id: str - item_id: str - logprobs: Optional[list[LogProbProperties]] - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA] + class azure.ai.projects.models.LiveSpecificCustomToolParam(_Model): + name: str + type: Literal["custom"] @overload def __init__( self, *, - content_index: Optional[int] = ..., - delta: Optional[str] = ..., - event_id: str, - item_id: str, - logprobs: Optional[list[LogProbProperties]] = ... + name: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionFailed(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.failed'): - content_index: int - error: RealtimeServerEventConversationItemInputAudioTranscriptionFailedError - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED] + class azure.ai.projects.models.LiveSpecificFileSearchParam(_Model): + type: Literal["file_search"] - @overload def __init__( self, - *, - content_index: int, - error: RealtimeServerEventConversationItemInputAudioTranscriptionFailedError, - event_id: str, - item_id: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError(_Model): - code: Optional[str] - message: Optional[str] - param: Optional[str] - type: Optional[str] + class azure.ai.projects.models.LiveSpecificFunctionShellParam(_Model): + type: Literal["shell"] - @overload def __init__( self, - *, - code: Optional[str] = ..., - message: Optional[str] = ..., - param: Optional[str] = ..., - type: Optional[str] = ... + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionSegment(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.segment'): - content_index: int - end: float - event_id: str - id: str - item_id: str - speaker: str - start: float - text: str - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT] + class azure.ai.projects.models.LiveSpecificImageGenParam(_Model): + type: Literal["image_generation"] - @overload def __init__( self, - *, - content_index: int, - end: float, - event_id: str, - id: str, - item_id: str, - speaker: str, - start: float, - text: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventConversationItemRetrieved(RealtimeServerEvent, discriminator='conversation.item.retrieved'): - event_id: str - item: RealtimeConversationItem - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_RETRIEVED] + class azure.ai.projects.models.LiveSpecificProgrammaticToolCallingParam(_Model): + type: Literal["programmatic_tool_calling"] - @overload def __init__( self, - *, - event_id: str, - item: RealtimeConversationItem + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.LiveSpecificWebSearchParam(_Model): + type: Literal["web_search"] - class azure.ai.projects.models.RealtimeServerEventConversationItemTruncated(RealtimeServerEvent, discriminator='conversation.item.truncated'): - audio_end_ms: int - content_index: int - event_id: str - item: Optional[RealtimeConversationItem] - item_id: str - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_TRUNCATED] + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + + class azure.ai.projects.models.LiveSpecificWebSearchPreviewParam(_Model): + type: Literal["web_search_preview"] - @overload def __init__( self, - *, - audio_end_ms: int, - content_index: int, - event_id: str, - item: Optional[RealtimeConversationItem] = ..., - item_id: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.LiveTextVerbosity(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + MEDIUM = "medium" - class azure.ai.projects.models.RealtimeServerEventError(_Model): - error: RealtimeServerEventErrorError - event_id: str - type: Literal["error"] + class azure.ai.projects.models.LiveToolChoiceEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + NONE = "none" + REQUIRED = "required" + + + class azure.ai.projects.models.LiveToolChoiceValueEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + NONE = "none" + REQUIRED = "required" + + + class azure.ai.projects.models.LiveToolSearchToolInputParam(_Model): + type: Literal["tool_search"] - @overload def __init__( self, - *, - error: RealtimeServerEventErrorError, - event_id: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventErrorError(_Model): - code: Optional[str] - event_id: Optional[str] + class azure.ai.projects.models.LiveTransportCallError(_Model): + code: str message: str param: Optional[str] - type: str + type: Literal["call_error"] @overload def __init__( self, *, - code: Optional[str] = ..., - event_id: Optional[str] = ..., + code: str, message: str, - param: Optional[str] = ..., - type: str + param: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventInputAudioBufferCleared(RealtimeServerEvent, discriminator='input_audio_buffer.cleared'): - event_id: str - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_CLEARED] + class azure.ai.projects.models.LiveWebSearchToolInputParam(_Model): + type: Literal["web_search"] - @overload def __init__( self, - *, - event_id: str + *args: Any, + **kwargs: Any ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - class azure.ai.projects.models.RealtimeServerEventInputAudioBufferCommitted(RealtimeServerEvent, discriminator='input_audio_buffer.committed'): - event_id: str - item_id: str - previous_item_id: Optional[str] - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_COMMITTED] + class azure.ai.projects.models.LocalShellToolParam(Tool, discriminator='local_shell'): + description: Optional[str] + name: Optional[str] + tool_configs: Optional[dict[str, ToolConfig]] + type: Literal[ToolType.LOCAL_SHELL] @overload def __init__( self, *, - event_id: str, - item_id: str, - previous_item_id: Optional[str] = ... + description: Optional[str] = ..., + name: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventInputAudioBufferSpeechStarted(RealtimeServerEvent, discriminator='input_audio_buffer.speech_started'): - audio_start_ms: int - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED] + class azure.ai.projects.models.LocalSkillParam(_Model): + description: str + name: str + path: str @overload def __init__( self, *, - audio_start_ms: int, - event_id: str, - item_id: str + description: str, + name: str, + path: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventInputAudioBufferSpeechStopped(RealtimeServerEvent, discriminator='input_audio_buffer.speech_stopped'): - audio_end_ms: int - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STOPPED] + class azure.ai.projects.models.LogProbProperties(_Model): + bytes: list[int] + logprob: float + token: str @overload def __init__( self, *, - audio_end_ms: int, - event_id: str, - item_id: str + bytes: list[int], + logprob: float, + token: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventInputAudioBufferTimeoutTriggered(RealtimeServerEvent, discriminator='input_audio_buffer.timeout_triggered'): - audio_end_ms: int - audio_start_ms: int - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED] + class azure.ai.projects.models.LoraConfig(_Model): + alpha: Optional[int] + dropout: Optional[float] + rank: Optional[int] + target_modules: Optional[list[str]] @overload def __init__( self, *, - audio_end_ms: int, - audio_start_ms: int, - event_id: str, - item_id: str + alpha: Optional[int] = ..., + dropout: Optional[float] = ..., + rank: Optional[int] = ..., + target_modules: Optional[list[str]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventMCPListToolsCompleted(RealtimeServerEvent, discriminator='mcp_list_tools.completed'): - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_COMPLETED] + class azure.ai.projects.models.MCPListToolsTool(_Model): + annotations: Optional[MCPListToolsToolAnnotations] + description: Optional[str] + input_schema: MCPListToolsToolInputSchema + name: str @overload def __init__( self, *, - event_id: str, - item_id: str + annotations: Optional[MCPListToolsToolAnnotations] = ..., + description: Optional[str] = ..., + input_schema: MCPListToolsToolInputSchema, + name: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventMCPListToolsFailed(RealtimeServerEvent, discriminator='mcp_list_tools.failed'): - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_FAILED] + class azure.ai.projects.models.MCPListToolsToolAnnotations(_Model): + + + class azure.ai.projects.models.MCPListToolsToolInputSchema(_Model): + + + class azure.ai.projects.models.MCPTool(Tool, discriminator='mcp'): + allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] + allowed_tools: Optional[Union[list[str], MCPToolFilter]] + authorization: Optional[str] + connector_id: Optional[Literal["connector_dropbox", "connector_gmail", "connector_googlecalendar", "connector_googledrive", "connector_microsoftteams", "connector_outlookcalendar", "connector_outlookemail", "connector_sharepoint"]] + defer_loading: Optional[bool] + headers: Optional[dict[str, str]] + project_connection_id: Optional[str] + require_approval: Optional[Union[MCPToolRequireApproval, Literal["always"], Literal["never"]]] + server_description: Optional[str] + server_label: str + server_url: Optional[str] + tool_configs: Optional[dict[str, ToolConfig]] + tunnel_id: Optional[str] + type: Literal[ToolType.MCP] @overload def __init__( self, *, - event_id: str, - item_id: str + allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] = ..., + allowed_tools: Optional[Union[list[str], MCPToolFilter]] = ..., + authorization: Optional[str] = ..., + connector_id: Optional[Literal[connector_dropbox, connector_gmail, connector_googlecalendar, connector_googledrive, connector_microsoftteams, connector_outlookcalendar, connector_outlookemail, connector_sharepoint]] = ..., + defer_loading: Optional[bool] = ..., + headers: Optional[dict[str, str]] = ..., + project_connection_id: Optional[str] = ..., + require_approval: Optional[Union[MCPToolRequireApproval, Literal[always], Literal[never]]] = ..., + server_description: Optional[str] = ..., + server_label: str, + server_url: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ..., + tunnel_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventMCPListToolsInProgress(RealtimeServerEvent, discriminator='mcp_list_tools.in_progress'): - event_id: str - item_id: str - type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_IN_PROGRESS] + class azure.ai.projects.models.MCPToolFilter(_Model): + read_only: Optional[bool] + tool_names: Optional[list[str]] @overload def __init__( self, *, - event_id: str, - item_id: str + read_only: Optional[bool] = ..., + tool_names: Optional[list[str]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventOutputAudioBufferCleared(RealtimeServerEvent, discriminator='output_audio_buffer.cleared'): - event_id: str - response_id: str - type: Literal[RealtimeServerEventType.OUTPUT_AUDIO_BUFFER_CLEARED] + class azure.ai.projects.models.MCPToolRequireApproval(_Model): + always: Optional[MCPToolFilter] + never: Optional[MCPToolFilter] @overload def __init__( self, *, - event_id: str, - response_id: str + always: Optional[MCPToolFilter] = ..., + never: Optional[MCPToolFilter] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventRateLimitsUpdated(RealtimeServerEvent, discriminator='rate_limits.updated'): - event_id: str - rate_limits: list[RealtimeServerEventRateLimitsUpdatedRateLimits] - type: Literal[RealtimeServerEventType.RATE_LIMITS_UPDATED] + class azure.ai.projects.models.MCPToolboxTool(ToolboxTool, discriminator='mcp'): + allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] + allowed_tools: Optional[Union[list[str], MCPToolFilter]] + authorization: Optional[str] + connector_id: Optional[Literal["connector_dropbox", "connector_gmail", "connector_googlecalendar", "connector_googledrive", "connector_microsoftteams", "connector_outlookcalendar", "connector_outlookemail", "connector_sharepoint"]] + defer_loading: Optional[bool] + description: str + headers: Optional[dict[str, str]] + name: str + project_connection_id: Optional[str] + require_approval: Optional[Union[MCPToolRequireApproval, Literal["always"], Literal["never"]]] + server_description: Optional[str] + server_label: str + server_url: Optional[str] + tool_configs: dict[str, ToolConfig] + tunnel_id: Optional[str] + type: Literal[ToolboxToolType.MCP] @overload def __init__( self, *, - event_id: str, - rate_limits: list[RealtimeServerEventRateLimitsUpdatedRateLimits] + allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] = ..., + allowed_tools: Optional[Union[list[str], MCPToolFilter]] = ..., + authorization: Optional[str] = ..., + connector_id: Optional[Literal[connector_dropbox, connector_gmail, connector_googlecalendar, connector_googledrive, connector_microsoftteams, connector_outlookcalendar, connector_outlookemail, connector_sharepoint]] = ..., + defer_loading: Optional[bool] = ..., + description: Optional[str] = ..., + headers: Optional[dict[str, str]] = ..., + name: Optional[str] = ..., + project_connection_id: Optional[str] = ..., + require_approval: Optional[Union[MCPToolRequireApproval, Literal[always], Literal[never]]] = ..., + server_description: Optional[str] = ..., + server_label: str, + server_url: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ..., + tunnel_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventRateLimitsUpdatedRateLimits(_Model): - limit: Optional[int] - name: Optional[Literal["requests", "tokens"]] - remaining: Optional[int] - reset_seconds: Optional[float] + class azure.ai.projects.models.ManagedAgentIdentityBlueprintReference(AgentBlueprintReference, discriminator='ManagedAgentIdentityBlueprint'): + blueprint_id: str + type: Literal[AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT] @overload def __init__( self, *, - limit: Optional[int] = ..., - name: Optional[Literal[requests, tokens]] = ..., - remaining: Optional[int] = ..., - reset_seconds: Optional[float] = ... + blueprint_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseAudioDelta(RealtimeServerEvent, discriminator='response.output_audio.delta'): - content_index: int - delta: bytes - event_id: str - item_id: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DELTA] + class azure.ai.projects.models.ManagedAzureAISearchIndex(Index, discriminator='ManagedAzureSearch'): + description: str + id: str + name: str + tags: dict[str, str] + type: Literal[IndexType.MANAGED_AZURE_SEARCH] + vector_store_id: str + version: str @overload def __init__( self, *, - content_index: int, - delta: bytes, - event_id: str, - item_id: str, - output_index: int, - response_id: str + description: Optional[str] = ..., + tags: Optional[dict[str, str]] = ..., + vector_store_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseAudioDone(RealtimeServerEvent, discriminator='response.output_audio.done'): - content_index: int - event_id: str - item_id: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DONE] + class azure.ai.projects.models.McpProtocolConfiguration(_Model): + + + class azure.ai.projects.models.MemoryItem(_Model): + content: str + kind: str + memory_id: str + scope: str + updated_at: datetime @overload def __init__( self, *, - content_index: int, - event_id: str, - item_id: str, - output_index: int, - response_id: str + content: str, + kind: str, + memory_id: str, + scope: str, + updated_at: datetime ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseAudioTranscriptDelta(RealtimeServerEvent, discriminator='response.output_audio_transcript.delta'): - content_index: int - delta: str - event_id: str - item_id: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA] + class azure.ai.projects.models.MemoryItemKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CHAT_SUMMARY = "chat_summary" + PROCEDURAL = "procedural" + USER_PROFILE = "user_profile" + + + class azure.ai.projects.models.MemoryOperation(_Model): + kind: Union[str, MemoryOperationKind] + memory_item: MemoryItem @overload def __init__( self, *, - content_index: int, - delta: str, - event_id: str, - item_id: str, - output_index: int, - response_id: str + kind: Union[str, MemoryOperationKind], + memory_item: MemoryItem ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseAudioTranscriptDone(RealtimeServerEvent, discriminator='response.output_audio_transcript.done'): - content_index: int - event_id: str - item_id: str - output_index: int - response_id: str - transcript: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE] + class azure.ai.projects.models.MemoryOperationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CREATE = "create" + DELETE = "delete" + UPDATE = "update" + + + class azure.ai.projects.models.MemorySearchItem(_Model): + memory_item: MemoryItem @overload def __init__( self, *, - content_index: int, - event_id: str, - item_id: str, - output_index: int, - response_id: str, - transcript: str + memory_item: MemoryItem ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseContentPartAdded(RealtimeServerEvent, discriminator='response.content_part.added'): - content_index: int - event_id: str - item_id: str - output_index: int - part: RealtimeServerEventResponseContentPartAddedPart - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_ADDED] + class azure.ai.projects.models.MemorySearchOptions(_Model): + max_memories: Optional[int] @overload def __init__( self, *, - content_index: int, - event_id: str, - item_id: str, - output_index: int, - part: RealtimeServerEventResponseContentPartAddedPart, - response_id: str + max_memories: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseContentPartAddedPart(_Model): - audio: Optional[str] - text: Optional[str] - transcript: Optional[str] - type: Optional[Literal["audio", "text"]] + class azure.ai.projects.models.MemorySearchPreviewTool(Tool, discriminator='memory_search_preview'): + memory_store_name: str + scope: str + search_options: Optional[MemorySearchOptions] + type: Literal[ToolType.MEMORY_SEARCH_PREVIEW] + update_delay: Optional[int] @overload def __init__( self, *, - audio: Optional[str] = ..., - text: Optional[str] = ..., - transcript: Optional[str] = ..., - type: Optional[Literal[audio, text]] = ... + memory_store_name: str, + scope: str, + search_options: Optional[MemorySearchOptions] = ..., + update_delay: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseContentPartDone(RealtimeServerEvent, discriminator='response.content_part.done'): - content_index: int - event_id: str - item_id: str - output_index: int - part: RealtimeServerEventResponseContentPartDonePart - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_DONE] + class azure.ai.projects.models.MemoryStoreDefaultDefinition(MemoryStoreDefinition, discriminator='default'): + chat_model: str + embedding_model: str + kind: Literal[MemoryStoreKind.DEFAULT] + options: Optional[MemoryStoreDefaultOptions] @overload def __init__( self, *, - content_index: int, - event_id: str, - item_id: str, - output_index: int, - part: RealtimeServerEventResponseContentPartDonePart, - response_id: str + chat_model: str, + embedding_model: str, + options: Optional[MemoryStoreDefaultOptions] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseContentPartDonePart(_Model): - audio: Optional[str] - format: Optional[RealtimeAudioFormats] - text: Optional[str] - transcript: Optional[str] - type: Optional[Literal["audio", "text"]] + class azure.ai.projects.models.MemoryStoreDefaultOptions(_Model): + chat_summary_enabled: bool + default_ttl_seconds: Optional[timedelta] + procedural_memory_enabled: Optional[bool] + user_profile_details: Optional[str] + user_profile_enabled: bool @overload def __init__( self, *, - audio: Optional[str] = ..., - format: Optional[RealtimeAudioFormats] = ..., - text: Optional[str] = ..., - transcript: Optional[str] = ..., - type: Optional[Literal[audio, text]] = ... + chat_summary_enabled: bool, + default_ttl_seconds: Optional[timedelta] = ..., + procedural_memory_enabled: Optional[bool] = ..., + user_profile_details: Optional[str] = ..., + user_profile_enabled: bool ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseCreated(RealtimeServerEvent, discriminator='response.created'): - event_id: str - response: VoiceAgentRealtimeResponse - type: Literal[RealtimeServerEventType.RESPONSE_CREATED] + class azure.ai.projects.models.MemoryStoreDefinition(_Model): + kind: str @overload def __init__( self, *, - event_id: str, - response: VoiceAgentRealtimeResponse + kind: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseDone(RealtimeServerEvent, discriminator='response.done'): - event_id: str - response: VoiceAgentRealtimeResponse - type: Literal[RealtimeServerEventType.RESPONSE_DONE] + class azure.ai.projects.models.MemoryStoreDeleteScopeResult(_Model): + deleted: bool + name: str + object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED] + scope: str @overload def __init__( self, *, - event_id: str, - response: VoiceAgentRealtimeResponse + deleted: bool, + name: str, + object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED], + scope: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseFunctionCallArgumentsDelta(RealtimeServerEvent, discriminator='response.function_call_arguments.delta'): - call_id: str - delta: str - event_id: str - item_id: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA] + class azure.ai.projects.models.MemoryStoreDetails(_Model): + created_at: datetime + definition: MemoryStoreDefinition + description: Optional[str] + id: str + metadata: Optional[dict[str, str]] + name: str + object: Literal[MemoryStoreObjectType.MEMORY_STORE] + updated_at: datetime @overload def __init__( self, *, - call_id: str, - delta: str, - event_id: str, - item_id: str, - output_index: int, - response_id: str + created_at: datetime, + definition: MemoryStoreDefinition, + description: Optional[str] = ..., + id: str, + metadata: Optional[dict[str, str]] = ..., + name: str, + object: Literal[MemoryStoreObjectType.MEMORY_STORE], + updated_at: datetime ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseFunctionCallArgumentsDone(RealtimeServerEvent, discriminator='response.function_call_arguments.done'): - arguments: str - call_id: str - event_id: str - item_id: str - name: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE] + class azure.ai.projects.models.MemoryStoreKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DEFAULT = "default" + + + class azure.ai.projects.models.MemoryStoreObjectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + MEMORY_DELETED = "memory_store.item.deleted" + MEMORY_STORE = "memory_store" + MEMORY_STORE_DELETED = "memory_store.deleted" + MEMORY_STORE_SCOPE_DELETED = "memory_store.scope.deleted" + + + class azure.ai.projects.models.MemoryStoreOperationUsage(_Model): + embedding_tokens: int + input_tokens: int + input_tokens_details: ResponseUsageInputTokensDetails + output_tokens: int + output_tokens_details: ResponseUsageOutputTokensDetails + total_tokens: int @overload def __init__( self, *, - arguments: str, - call_id: str, - event_id: str, - item_id: str, - name: str, - output_index: int, - response_id: str + embedding_tokens: int, + input_tokens: int, + input_tokens_details: ResponseUsageInputTokensDetails, + output_tokens: int, + output_tokens_details: ResponseUsageOutputTokensDetails, + total_tokens: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseMCPCallArgumentsDelta(RealtimeServerEvent, discriminator='response.mcp_call_arguments.delta'): - delta: str - event_id: str - item_id: str - obfuscation: Optional[str] - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DELTA] + class azure.ai.projects.models.MemoryStoreSearchResult(_Model): + memories: list[MemorySearchItem] + search_id: str + usage: MemoryStoreOperationUsage @overload def __init__( self, *, - delta: str, - event_id: str, - item_id: str, - obfuscation: Optional[str] = ..., - output_index: int, - response_id: str + memories: list[MemorySearchItem], + search_id: str, + usage: MemoryStoreOperationUsage ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseMCPCallArgumentsDone(RealtimeServerEvent, discriminator='response.mcp_call_arguments.done'): - arguments: str - event_id: str - item_id: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DONE] + class azure.ai.projects.models.MemoryStoreUpdateCompletedResult(_Model): + memory_operations: list[MemoryOperation] + usage: MemoryStoreOperationUsage @overload def __init__( self, *, - arguments: str, - event_id: str, - item_id: str, - output_index: int, - response_id: str + memory_operations: list[MemoryOperation], + usage: MemoryStoreOperationUsage ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseMCPCallCompleted(RealtimeServerEvent, discriminator='response.mcp_call.completed'): - event_id: str - item_id: str - output_index: int - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_COMPLETED] + class azure.ai.projects.models.MemoryStoreUpdateResult(_Model): + error: Optional[ApiError] + result: Optional[MemoryStoreUpdateCompletedResult] + status: Union[str, MemoryStoreUpdateStatus] + superseded_by: Optional[str] + update_id: str @overload def __init__( self, *, - event_id: str, - item_id: str, - output_index: int + error: Optional[ApiError] = ..., + result: Optional[MemoryStoreUpdateCompletedResult] = ..., + status: Union[str, MemoryStoreUpdateStatus], + superseded_by: Optional[str] = ..., + update_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseMCPCallFailed(RealtimeServerEvent, discriminator='response.mcp_call.failed'): - event_id: str - item_id: str - output_index: int - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_FAILED] + class azure.ai.projects.models.MemoryStoreUpdateStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COMPLETED = "completed" + FAILED = "failed" + IN_PROGRESS = "in_progress" + QUEUED = "queued" + SUPERSEDED = "superseded" + + + class azure.ai.projects.models.Metadata(_Model): + + + class azure.ai.projects.models.Microsoft365PermissionScopes(_Model): + resource_app_id: str + scopes: list[str] @overload def __init__( self, *, - event_id: str, - item_id: str, - output_index: int + resource_app_id: str, + scopes: list[str] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseMCPCallInProgress(RealtimeServerEvent, discriminator='response.mcp_call.in_progress'): - event_id: str - item_id: str - output_index: int - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_IN_PROGRESS] + class azure.ai.projects.models.Microsoft365PublishDefaults(_Model): + agent_display_name: Optional[str] + agent_name: Optional[str] + app_publish_scope: Optional[Union[str, Microsoft365PublishScope]] + app_registration_client_id: Optional[str] + app_version: Optional[str] + bot_service_arm_id: Optional[str] + developer_name: Optional[str] + developer_website_url: Optional[str] + full_description: Optional[str] + privacy_url: Optional[str] + recommended_next_app_version: Optional[str] + short_description: Optional[str] + teams_app_id: Optional[str] + terms_of_use_url: Optional[str] + title_id: Optional[str] @overload def __init__( self, *, - event_id: str, - item_id: str, - output_index: int + agent_display_name: Optional[str] = ..., + agent_name: Optional[str] = ..., + app_publish_scope: Optional[Union[str, Microsoft365PublishScope]] = ..., + app_registration_client_id: Optional[str] = ..., + app_version: Optional[str] = ..., + bot_service_arm_id: Optional[str] = ..., + developer_name: Optional[str] = ..., + developer_website_url: Optional[str] = ..., + full_description: Optional[str] = ..., + privacy_url: Optional[str] = ..., + recommended_next_app_version: Optional[str] = ..., + short_description: Optional[str] = ..., + teams_app_id: Optional[str] = ..., + terms_of_use_url: Optional[str] = ..., + title_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseOutputItemAdded(RealtimeServerEvent, discriminator='response.output_item.added'): - event_id: str - item: RealtimeConversationItem - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_ADDED] + class azure.ai.projects.models.Microsoft365PublishResult(_Model): + teams_app_id: Optional[str] + title_id: Optional[str] @overload def __init__( self, *, - event_id: str, - item: RealtimeConversationItem, - output_index: int, - response_id: str + teams_app_id: Optional[str] = ..., + title_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseOutputItemDone(RealtimeServerEvent, discriminator='response.output_item.done'): - event_id: str - item: RealtimeConversationItem - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_DONE] + class azure.ai.projects.models.Microsoft365PublishScope(str, Enum, metaclass=CaseInsensitiveEnumMeta): + PERSONAL = "Personal" + SHARED = "Shared" + TENANT = "Tenant" + + + class azure.ai.projects.models.MicrosoftCopilotBuiltInTool(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FILESYSTEM_READ = "filesystem_read" + FILESYSTEM_WRITE = "filesystem_write" + SHELL = "shell" + SUBAGENTS = "subagents" + WEB = "web" + + + class azure.ai.projects.models.MicrosoftCopilotHarness(AgentHarness, discriminator='microsoft_copilot_preview'): + type: Literal["microsoft_copilot_preview"] @overload - def __init__( - self, - *, - event_id: str, - item: RealtimeConversationItem, - output_index: int, - response_id: str - ) -> None: ... + def __init__(self) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseTextDelta(RealtimeServerEvent, discriminator='response.output_text.delta'): - content_index: int - delta: str - event_id: str - item_id: str - output_index: int - response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DELTA] + class azure.ai.projects.models.MicrosoftCopilotToolsetConfig(_Model): + enabled: Optional[bool] + name: Union[str, MicrosoftCopilotBuiltInTool] @overload def __init__( self, *, - content_index: int, - delta: str, - event_id: str, - item_id: str, - output_index: int, - response_id: str + enabled: Optional[bool] = ..., + name: Union[str, MicrosoftCopilotBuiltInTool] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventResponseTextDone(RealtimeServerEvent, discriminator='response.output_text.done'): - content_index: int - event_id: str - item_id: str - output_index: int - response_id: str - text: str - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DONE] + class azure.ai.projects.models.MicrosoftCopilotToolsetDefaultConfig(_Model): + enabled: Optional[bool] @overload def __init__( self, *, - content_index: int, - event_id: str, - item_id: str, - output_index: int, - response_id: str, - text: str + enabled: Optional[bool] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventSessionCreated(RealtimeServerEvent, discriminator='session.created'): - conversation_id: Optional[str] - event_id: str - session: VoiceAgentSessionResponse - type: Literal[RealtimeServerEventType.SESSION_CREATED] + class azure.ai.projects.models.MicrosoftCopilotToolsetPreview(Tool, discriminator='microsoft_copilot_toolset_preview'): + configs: Optional[list[MicrosoftCopilotToolsetConfig]] + default_config: Optional[MicrosoftCopilotToolsetDefaultConfig] + type: Literal[ToolType.MICROSOFT_COPILOT_TOOLSET_PREVIEW] @overload def __init__( self, *, - conversation_id: Optional[str] = ..., - event_id: str, - session: VoiceAgentSessionResponse + configs: Optional[list[MicrosoftCopilotToolsetConfig]] = ..., + default_config: Optional[MicrosoftCopilotToolsetDefaultConfig] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventSessionUpdated(RealtimeServerEvent, discriminator='session.updated'): - event_id: str - session: VoiceAgentSessionResponse - type: Literal[RealtimeServerEventType.SESSION_UPDATED] + class azure.ai.projects.models.MicrosoftFabricPreviewTool(Tool, discriminator='fabric_dataagent_preview'): + fabric_dataagent_preview: FabricDataAgentToolParameters + type: Literal[ToolType.FABRIC_DATAAGENT_PREVIEW] @overload def __init__( self, *, - event_id: str, - session: VoiceAgentSessionResponse + fabric_dataagent_preview: FabricDataAgentToolParameters ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RealtimeServerEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CONVERSATION_CREATED = "conversation.created" - CONVERSATION_ITEM_ADDED = "conversation.item.added" - CONVERSATION_ITEM_CREATED = "conversation.item.created" - CONVERSATION_ITEM_DELETED = "conversation.item.deleted" - CONVERSATION_ITEM_DONE = "conversation.item.done" - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED = "conversation.item.input_audio_transcription.completed" - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA = "conversation.item.input_audio_transcription.delta" - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED = "conversation.item.input_audio_transcription.failed" - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT = "conversation.item.input_audio_transcription.segment" - CONVERSATION_ITEM_RETRIEVED = "conversation.item.retrieved" - CONVERSATION_ITEM_TRUNCATED = "conversation.item.truncated" - ERROR = "error" - INPUT_AUDIO_BUFFER_CLEARED = "input_audio_buffer.cleared" - INPUT_AUDIO_BUFFER_COMMITTED = "input_audio_buffer.committed" - INPUT_AUDIO_BUFFER_DTMF_EVENT_RECEIVED = "input_audio_buffer.dtmf_event_received" - INPUT_AUDIO_BUFFER_SPEECH_STARTED = "input_audio_buffer.speech_started" - INPUT_AUDIO_BUFFER_SPEECH_STOPPED = "input_audio_buffer.speech_stopped" - INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED = "input_audio_buffer.timeout_triggered" - MCP_LIST_TOOLS_COMPLETED = "mcp_list_tools.completed" - MCP_LIST_TOOLS_FAILED = "mcp_list_tools.failed" - MCP_LIST_TOOLS_IN_PROGRESS = "mcp_list_tools.in_progress" - OUTPUT_AUDIO_BUFFER_CLEARED = "output_audio_buffer.cleared" - OUTPUT_AUDIO_BUFFER_STARTED = "output_audio_buffer.started" - OUTPUT_AUDIO_BUFFER_STOPPED = "output_audio_buffer.stopped" - RATE_LIMITS_UPDATED = "rate_limits.updated" - RESPONSE_ANIMATION_BLENDSHAPES_DELTA = "response.animation_blendshapes.delta" - RESPONSE_ANIMATION_BLENDSHAPES_DONE = "response.animation_blendshapes.done" - RESPONSE_ANIMATION_VISEME_DELTA = "response.animation_viseme.delta" - RESPONSE_ANIMATION_VISEME_DONE = "response.animation_viseme.done" - RESPONSE_AUDIO_TIMESTAMP_DELTA = "response.audio_timestamp.delta" - RESPONSE_AUDIO_TIMESTAMP_DONE = "response.audio_timestamp.done" - RESPONSE_CONTENT_PART_ADDED = "response.content_part.added" - RESPONSE_CONTENT_PART_DONE = "response.content_part.done" - RESPONSE_CREATED = "response.created" - RESPONSE_DONE = "response.done" - RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA = "response.function_call_arguments.delta" - RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE = "response.function_call_arguments.done" - RESPONSE_MCP_CALL_ARGUMENTS_DELTA = "response.mcp_call_arguments.delta" - RESPONSE_MCP_CALL_ARGUMENTS_DONE = "response.mcp_call_arguments.done" - RESPONSE_MCP_CALL_COMPLETED = "response.mcp_call.completed" - RESPONSE_MCP_CALL_FAILED = "response.mcp_call.failed" - RESPONSE_MCP_CALL_IN_PROGRESS = "response.mcp_call.in_progress" - RESPONSE_OUTPUT_AUDIO_DELTA = "response.output_audio.delta" - RESPONSE_OUTPUT_AUDIO_DONE = "response.output_audio.done" - RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA = "response.output_audio_transcript.delta" - RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE = "response.output_audio_transcript.done" - RESPONSE_OUTPUT_ITEM_ADDED = "response.output_item.added" - RESPONSE_OUTPUT_ITEM_DONE = "response.output_item.done" - RESPONSE_OUTPUT_TEXT_DELTA = "response.output_text.delta" - RESPONSE_OUTPUT_TEXT_DONE = "response.output_text.done" - RESPONSE_VIDEO_DELTA = "response.video.delta" - RTC_CALL_ERROR = "rtc.call.error" - RTC_CALL_SDP_CREATED = "rtc.call.sdp.created" - SESSION_AVATAR_CONNECTING = "session.avatar.connecting" - SESSION_AVATAR_SWITCH_TO_IDLE = "session.avatar.switch_to_idle" - SESSION_AVATAR_SWITCH_TO_SPEAKING = "session.avatar.switch_to_speaking" - SESSION_CREATED = "session.created" - SESSION_SUBAGENT_ABORTED = "session.subagent.aborted" - SESSION_SUBAGENT_COMPLETED = "session.subagent.completed" - SESSION_SUBAGENT_STARTED = "session.subagent.started" - SESSION_UPDATED = "session.updated" - WARNING = "warning" - - - class azure.ai.projects.models.Reasoning(_Model): - context: Optional[Literal["auto", "current_turn", "all_turns"]] - effort: Optional[Union[str, ReasoningEffort]] - generate_summary: Optional[Literal["auto", "concise", "detailed"]] - mode: Optional[Union[str, ReasoningModeEnum]] - summary: Optional[Literal["auto", "concise", "detailed"]] + class azure.ai.projects.models.MisalignmentErrorDetailsResource(_Model): + detailed_explanation: Optional[str] + error_type: Optional[Union[str, MisalignmentErrorType]] + review_target: Optional[str] + steer: Optional[MisalignmentSteer] @overload def __init__( self, *, - context: Optional[Literal[auto, current_turn, all_turns]] = ..., - effort: Optional[Union[str, ReasoningEffort]] = ..., - generate_summary: Optional[Literal[auto, concise, detailed]] = ..., - mode: Optional[Union[str, ReasoningModeEnum]] = ..., - summary: Optional[Literal[auto, concise, detailed]] = ... + detailed_explanation: Optional[str] = ..., + error_type: Optional[Union[str, MisalignmentErrorType]] = ..., + review_target: Optional[str] = ..., + steer: Optional[MisalignmentSteer] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): - HIGH = "high" - LOW = "low" - MAX = "max" - MEDIUM = "medium" - MINIMAL = "minimal" - NONE = "none" - XHIGH = "xhigh" - - - class azure.ai.projects.models.ReasoningModeEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): - PRO = "pro" - STANDARD = "standard" + class azure.ai.projects.models.MisalignmentErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + OTHER = "other" + POTENTIALLY_UNINTENDED_DATA_ACCESS = "potentially_unintended_data_access" + POTENTIALLY_UNINTENDED_DATA_TRANSFER = "potentially_unintended_data_transfer" + POTENTIALLY_UNINTENDED_DESTRUCTIVE_ACTIVITY = "potentially_unintended_destructive_activity" - class azure.ai.projects.models.RecurrenceSchedule(_Model): - type: str + class azure.ai.projects.models.MisalignmentSteer(_Model): + message: str @overload def __init__( self, *, - type: str + message: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RecurrenceTrigger(Trigger, discriminator='Recurrence'): - end_time: Optional[datetime] - interval: int - schedule: RecurrenceSchedule - start_time: Optional[datetime] - time_zone: Optional[str] - type: Literal[TriggerType.RECURRENCE] + class azure.ai.projects.models.ModelCredentialRequest(_Model): + blob_uri: str @overload def __init__( self, *, - end_time: Optional[datetime] = ..., - interval: int, - schedule: RecurrenceSchedule, - start_time: Optional[datetime] = ..., - time_zone: Optional[str] = ... + blob_uri: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RecurrenceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - DAILY = "Daily" - HOURLY = "Hourly" - MONTHLY = "Monthly" - WEEKLY = "Weekly" + class azure.ai.projects.models.ModelDeployment(Deployment, discriminator='ModelDeployment'): + capabilities: dict[str, str] + connection_name: Optional[str] + model_name: str + model_publisher: str + model_version: str + name: str + sku: ModelDeploymentSku + type: Literal[DeploymentType.MODEL_DEPLOYMENT] + @overload + def __init__(self) -> None: ... - class azure.ai.projects.models.RedTeam(_Model): - application_scenario: Optional[str] - attack_strategies: Optional[list[Union[str, AttackStrategy]]] - display_name: Optional[str] + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ModelDeploymentSku(_Model): + capacity: int + family: str name: str - num_turns: Optional[int] - properties: Optional[dict[str, str]] - risk_categories: Optional[list[Union[str, RiskCategory]]] - simulation_only: Optional[bool] - status: Optional[str] - tags: Optional[dict[str, str]] - target: RedTeamTargetConfig + size: str + tier: str @overload def __init__( self, *, - application_scenario: Optional[str] = ..., - attack_strategies: Optional[list[Union[str, AttackStrategy]]] = ..., - display_name: Optional[str] = ..., - num_turns: Optional[int] = ..., - properties: Optional[dict[str, str]] = ..., - risk_categories: Optional[list[Union[str, RiskCategory]]] = ..., - simulation_only: Optional[bool] = ..., - tags: Optional[dict[str, str]] = ..., - target: RedTeamTargetConfig + capacity: int, + family: str, + name: str, + size: str, + tier: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RedTeamEvalRunDataSource(TypedDict, total=False): - key "item_generation_params": Required[Any] - key "target": Required[Union[AzureAIAgentTargetParam, AzureAIModelTargetParam, dict[str, Any]]] - key "type": Required[Literal["azure_ai_red_team"]] + class azure.ai.projects.models.ModelIdsLive(str, Enum, metaclass=CaseInsensitiveEnumMeta): + GPT_LIVE1 = "gpt-live-1" - class azure.ai.projects.models.RedTeamTargetConfig(_Model): - type: str + class azure.ai.projects.models.ModelPendingUploadRequest(_Model): + connection_name: Optional[str] + pending_upload_id: Optional[str] + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] @overload def __init__( self, *, - type: str + connection_name: Optional[str] = ..., + pending_upload_id: Optional[str] = ..., + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ReinforcementFineTuningDataGenerationJob(DataGenerationJob, discriminator='reinforcement_finetuning_preview'): - created_at: datetime - error: ApiError - finished_at: datetime - generation_configuration: DataGenerationJobConfiguration - id: str - name: str - output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] - result: DataGenerationJobResult - scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] - sources: list[DataGenerationJobSource] - status: Union[str, JobStatus] + class azure.ai.projects.models.ModelPendingUploadResponse(_Model): + blob_reference: BlobReference + pending_upload_id: str + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] + version: Optional[str] @overload def __init__( self, *, - generation_configuration: DataGenerationJobConfiguration, - name: str, - output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] = ..., - sources: list[DataGenerationJobSource] + blob_reference: BlobReference, + pending_upload_id: str, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + version: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobInputs(DataGenerationJobInputs, discriminator='reinforcement_finetuning_preview'): - generation_configuration: DataGenerationJobConfiguration - name: str - output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] - scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] - sources: list[DataGenerationJobSource] + class azure.ai.projects.models.ModelSamplingConfigParam(TypedDict, total=False): + key "max_completion_tokens": int + key "seed": int + key "temperature": float + key "top_p": float + + + class azure.ai.projects.models.ModelSamplingParams(_Model): + max_completion_tokens: Optional[int] + seed: Optional[int] + temperature: Optional[float] + top_p: Optional[float] @overload def __init__( self, *, - generation_configuration: DataGenerationJobConfiguration, - name: str, - output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] = ..., - sources: list[DataGenerationJobSource] + max_completion_tokens: Optional[int] = ..., + seed: Optional[int] = ..., + temperature: Optional[float] = ..., + top_p: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobOutputConfiguration(_Model): - merge_file_id: Optional[str] - name: str - write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] + class azure.ai.projects.models.ModelSourceData(_Model): + job_id: Optional[str] + source_type: Optional[Union[str, FoundryModelSourceType]] @overload def __init__( self, *, - merge_file_id: Optional[str] = ..., - name: str, - write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] = ... + job_id: Optional[str] = ..., + source_type: Optional[Union[str, FoundryModelSourceType]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ReminderPreviewToolboxTool(ToolboxTool, discriminator='reminder_preview'): - description: str + class azure.ai.projects.models.ModelVersion(_Model): + artifact_profile: Optional[ArtifactProfile] + base_model: Optional[str] + blob_uri: str + description: Optional[str] + id: Optional[str] + lora_config: Optional[LoraConfig] name: str - tool_configs: dict[str, ToolConfig] - type: Literal[ToolboxToolType.REMINDER_PREVIEW] + source: Optional[ModelSourceData] + tags: Optional[dict[str, str]] + version: str + warnings: Optional[list[FoundryModelWarning]] + weight_type: Optional[Union[str, FoundryModelWeightType]] @overload def __init__( self, *, + base_model: Optional[str] = ..., + blob_uri: str, description: Optional[str] = ..., - name: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ... + lora_config: Optional[LoraConfig] = ..., + source: Optional[ModelSourceData] = ..., + tags: Optional[dict[str, str]] = ..., + weight_type: Optional[Union[str, FoundryModelWeightType]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ResponseRetrievalItemGenerationParams(TypedDict, total=False): - key "data_mapping": Required[Dict[str, str]] - key "max_num_turns": int - key "source": Required[Union[SourceFileContent, SourceFileID]] - key "type": Required[Literal["response_retrieval"]] - - - class azure.ai.projects.models.ResponseUsageInputTokensDetails(_Model): - cache_write_tokens: int - cached_tokens: int + class azure.ai.projects.models.MonthlyRecurrenceSchedule(RecurrenceSchedule, discriminator='Monthly'): + days_of_month: list[int] + type: Literal[RecurrenceType.MONTHLY] @overload def __init__( self, *, - cache_write_tokens: int, - cached_tokens: int + days_of_month: list[int] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ResponseUsageOutputTokensDetails(_Model): - reasoning_tokens: int + class azure.ai.projects.models.NamespaceToolParam(Tool, discriminator='namespace'): + description: str + name: str + tools: list[Union[FunctionToolParam, CustomToolParam]] + type: Literal[ToolType.NAMESPACE] @overload def __init__( self, *, - reasoning_tokens: int + description: str, + name: str, + tools: list[Union[FunctionToolParam, CustomToolParam]] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ResponsesProtocolConfiguration(_Model): - - - class azure.ai.projects.models.RiskCategory(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CODE_VULNERABILITY = "CodeVulnerability" - HATE_UNFAIRNESS = "HateUnfairness" - PROHIBITED_ACTIONS = "ProhibitedActions" - PROTECTED_MATERIAL = "ProtectedMaterial" - SELF_HARM = "SelfHarm" - SENSITIVE_DATA_LEAKAGE = "SensitiveDataLeakage" - SEXUAL = "Sexual" - TASK_ADHERENCE = "TaskAdherence" - UNGROUNDED_ATTRIBUTES = "UngroundedAttributes" - VIOLENCE = "Violence" - - - class azure.ai.projects.models.Routine(_Model): - action: Optional[RoutineAction] - created_at: Optional[datetime] - description: Optional[str] - enabled: bool - name: Optional[str] - triggers: Optional[dict[str, RoutineTrigger]] - updated_at: Optional[datetime] + class azure.ai.projects.models.NoAuthenticationCredentials(BaseCredentials, discriminator='None'): + type: Literal[CredentialType.NONE] @overload - def __init__( - self, - *, - action: Optional[RoutineAction] = ..., - created_at: Optional[datetime] = ..., - description: Optional[str] = ..., - enabled: bool, - name: Optional[str] = ..., - triggers: Optional[dict[str, RoutineTrigger]] = ..., - updated_at: Optional[datetime] = ... - ) -> None: ... + def __init__(self) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineAction(_Model): - type: str + class azure.ai.projects.models.OneTimeTrigger(Trigger, discriminator='OneTime'): + time_zone: Optional[str] + trigger_at: datetime + type: Literal[TriggerType.ONE_TIME] @overload def __init__( self, *, - type: str + time_zone: Optional[str] = ..., + trigger_at: datetime ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineActionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - INVOKE_AGENT_INVOCATIONS_API = "invoke_agent_invocations_api" - INVOKE_AGENT_RESPONSES_API = "invoke_agent_responses_api" + class azure.ai.projects.models.OpenApiAnonymousAuthDetails(OpenApiAuthDetails, discriminator='anonymous'): + type: Literal[OpenApiAuthType.ANONYMOUS] + @overload + def __init__(self) -> None: ... - class azure.ai.projects.models.RoutineAttemptSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): - EVENT_FIRE = "event_fire" - MANUAL_DISPATCH = "manual_dispatch" - QUEUED_DISPATCH = "queued_dispatch" - SCHEDULE_DELIVERY = "schedule_delivery" - TIMER_DELIVERY = "timer_delivery" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineAuthorization(_Model): - identity: Optional[Union[str, RoutineDispatchIdentity]] + class azure.ai.projects.models.OpenApiAuthDetails(_Model): + type: str @overload def __init__( self, *, - identity: Optional[Union[str, RoutineDispatchIdentity]] = ... + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineDispatchIdentity(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AGENT = "agent" - CREATOR = "creator" + class azure.ai.projects.models.OpenApiAuthType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ANONYMOUS = "anonymous" + MANAGED_IDENTITY = "managed_identity" + PROJECT_CONNECTION = "project_connection" - class azure.ai.projects.models.RoutineDispatchPayload(_Model): - type: str + class azure.ai.projects.models.OpenApiFunctionDefinition(_Model): + auth: OpenApiAuthDetails + default_params: Optional[list[str]] + description: Optional[str] + functions: Optional[list[OpenApiFunctionDefinitionFunction]] + name: str + spec: dict[str, Any] @overload def __init__( self, *, - type: str + auth: OpenApiAuthDetails, + default_params: Optional[list[str]] = ..., + description: Optional[str] = ..., + name: str, + spec: dict[str, Any] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineDispatchPayloadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - INVOKE_AGENT_INVOCATIONS_API = "invoke_agent_invocations_api" - INVOKE_AGENT_RESPONSES_API = "invoke_agent_responses_api" - - - class azure.ai.projects.models.RoutineRun(_Model): - action_correlation_id: Optional[str] - action_type: Optional[Union[str, RoutineActionType]] - agent_endpoint_id: Optional[str] - agent_id: Optional[str] - attempt_source: Optional[Union[str, RoutineAttemptSource]] - conversation_id: Optional[str] - dispatch_id: Optional[str] - ended_at: Optional[datetime] - error_message: Optional[str] - error_status_code: Optional[int] - error_type: Optional[str] - id: str - phase: Optional[Union[str, RoutineRunPhase]] - response_id: Optional[str] - scheduled_fire_at: Optional[datetime] - session_id: Optional[str] - started_at: Optional[datetime] - status: Optional[RoutineRunStatus] - task_id: Optional[str] - trigger_event_payload: Optional[dict[str, Any]] - trigger_name: Optional[str] - trigger_type: Optional[Union[str, RoutineTriggerType]] - triggered_at: Optional[datetime] + class azure.ai.projects.models.OpenApiFunctionDefinitionFunction(_Model): + description: Optional[str] + name: str + parameters: dict[str, Any] @overload def __init__( self, *, - action_correlation_id: Optional[str] = ..., - action_type: Optional[Union[str, RoutineActionType]] = ..., - agent_endpoint_id: Optional[str] = ..., - agent_id: Optional[str] = ..., - attempt_source: Optional[Union[str, RoutineAttemptSource]] = ..., - conversation_id: Optional[str] = ..., - dispatch_id: Optional[str] = ..., - ended_at: Optional[datetime] = ..., - error_message: Optional[str] = ..., - error_status_code: Optional[int] = ..., - error_type: Optional[str] = ..., - phase: Optional[Union[str, RoutineRunPhase]] = ..., - response_id: Optional[str] = ..., - scheduled_fire_at: Optional[datetime] = ..., - session_id: Optional[str] = ..., - started_at: Optional[datetime] = ..., - status: Optional[RoutineRunStatus] = ..., - task_id: Optional[str] = ..., - trigger_event_payload: Optional[dict[str, Any]] = ..., - trigger_name: Optional[str] = ..., - trigger_type: Optional[Union[str, RoutineTriggerType]] = ..., - triggered_at: Optional[datetime] = ... + description: Optional[str] = ..., + name: str, + parameters: dict[str, Any] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineRunPhase(str, Enum, metaclass=CaseInsensitiveEnumMeta): - COMPLETED = "completed" - DISPATCHING = "dispatching" - FAILED = "failed" - QUEUED = "queued" - - - class azure.ai.projects.models.RoutineTrigger(_Model): - type: str + class azure.ai.projects.models.OpenApiManagedAuthDetails(OpenApiAuthDetails, discriminator='managed_identity'): + security_scheme: OpenApiManagedSecurityScheme + type: Literal[OpenApiAuthType.MANAGED_IDENTITY] @overload def __init__( self, *, - type: str + security_scheme: OpenApiManagedSecurityScheme ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RoutineTriggerType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CUSTOM = "custom" - GITHUB_ISSUE = "github_issue" - SCHEDULE = "schedule" - TIMER = "timer" - - - class azure.ai.projects.models.RubricBasedEvaluatorDefinition(EvaluatorDefinition, discriminator='rubric'): - data_schema: dict[str, any] - dimensions: list[Dimension] - init_parameters: dict[str, any] - metrics: dict[str, EvaluatorMetric] - pass_threshold: Optional[float] - type: Literal[EvaluatorDefinitionType.RUBRIC] + class azure.ai.projects.models.OpenApiManagedSecurityScheme(_Model): + audience: str @overload def __init__( self, *, - data_schema: Optional[dict[str, Any]] = ..., - dimensions: list[Dimension], - init_parameters: Optional[dict[str, Any]] = ..., - metrics: Optional[dict[str, EvaluatorMetric]] = ..., - pass_threshold: Optional[float] = ... + audience: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RubricGenerationInputQualityWarning(_Model): - code: Union[str, RubricGenerationInputQualityWarningCode] - message: str - severity: Union[str, RubricGenerationInputQualityWarningSeverity] - source: Union[str, RubricGenerationInputQualityWarningSource] - source_index: Optional[int] + class azure.ai.projects.models.OpenApiProjectConnectionAuthDetails(OpenApiAuthDetails, discriminator='project_connection'): + security_scheme: OpenApiProjectConnectionSecurityScheme + type: Literal[OpenApiAuthType.PROJECT_CONNECTION] @overload def __init__( self, *, - code: Union[str, RubricGenerationInputQualityWarningCode], - message: str, - severity: Union[str, RubricGenerationInputQualityWarningSeverity], - source: Union[str, RubricGenerationInputQualityWarningSource], - source_index: Optional[int] = ... + security_scheme: OpenApiProjectConnectionSecurityScheme ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.RubricGenerationInputQualityWarningCode(str, Enum, metaclass=CaseInsensitiveEnumMeta): - EMPTY_AGENT_INSTRUCTIONS = "empty_agent_instructions" - EMPTY_DATASET_CONTENT = "empty_dataset_content" - EMPTY_PROMPT = "empty_prompt" - INSUFFICIENT_TOTAL_INPUT = "insufficient_total_input" - LOW_TRACE_COUNT = "low_trace_count" - SHORT_AGENT_INSTRUCTIONS = "short_agent_instructions" - SHORT_DATASET_CONTENT = "short_dataset_content" - SHORT_PROMPT = "short_prompt" - - - class azure.ai.projects.models.RubricGenerationInputQualityWarningSeverity(str, Enum, metaclass=CaseInsensitiveEnumMeta): - WARNING = "warning" + class azure.ai.projects.models.OpenApiProjectConnectionSecurityScheme(_Model): + project_connection_id: str + @overload + def __init__( + self, + *, + project_connection_id: str + ) -> None: ... - class azure.ai.projects.models.RubricGenerationInputQualityWarningSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AGENT = "agent" - AGGREGATE = "aggregate" - DATASET = "dataset" - PROMPT = "prompt" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SASCredentials(BaseCredentials, discriminator='SAS'): - sas_token: Optional[str] - type: Literal[CredentialType.SAS] + class azure.ai.projects.models.OpenApiTool(Tool, discriminator='openapi'): + openapi: OpenApiFunctionDefinition + tool_configs: Optional[dict[str, ToolConfig]] + type: Literal[ToolType.OPENAPI] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + openapi: OpenApiFunctionDefinition, + tool_configs: Optional[dict[str, ToolConfig]] = ... + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SampleType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - EVALUATION_RESULT_SAMPLE = "EvaluationResultSample" - - - class azure.ai.projects.models.Schedule(_Model): - description: Optional[str] - display_name: Optional[str] - enabled: bool - properties: Optional[dict[str, str]] - provisioning_status: Optional[Union[str, ScheduleProvisioningStatus]] - schedule_id: str - system_data: dict[str, str] - tags: Optional[dict[str, str]] - task: ScheduleTask - trigger: Trigger + class azure.ai.projects.models.OpenApiToolboxTool(ToolboxTool, discriminator='openapi'): + description: str + name: str + openapi: OpenApiFunctionDefinition + tool_configs: dict[str, ToolConfig] + type: Literal[ToolboxToolType.OPENAPI] @overload def __init__( self, *, description: Optional[str] = ..., - display_name: Optional[str] = ..., - enabled: bool, - properties: Optional[dict[str, str]] = ..., - tags: Optional[dict[str, str]] = ..., - task: ScheduleTask, - trigger: Trigger + name: Optional[str] = ..., + openapi: OpenApiFunctionDefinition, + tool_configs: Optional[dict[str, ToolConfig]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ScheduleProvisioningStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CREATING = "Creating" - DELETING = "Deleting" + class azure.ai.projects.models.OperationState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CANCELED = "Canceled" FAILED = "Failed" + NOT_STARTED = "NotStarted" + RUNNING = "Running" SUCCEEDED = "Succeeded" - UPDATING = "Updating" - class azure.ai.projects.models.ScheduleRoutineTrigger(RoutineTrigger, discriminator='schedule'): - cron_expression: str - time_zone: str - type: Literal[RoutineTriggerType.SCHEDULE] + class azure.ai.projects.models.OptimizationContext(_Model): + type: str @overload def __init__( self, *, - cron_expression: str, - time_zone: str + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ScheduleRun(_Model): - error: Optional[str] - properties: dict[str, str] - run_id: str - schedule_id: str - success: bool - trigger_time: Optional[datetime] + class azure.ai.projects.models.OptimizationContextType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + STEERING_PROMPT = "steering_prompt" - @overload - def __init__( - self, - *, - schedule_id: str, - trigger_time: Optional[datetime] = ... + + class azure.ai.projects.models.OtlpTelemetryEndpoint(TelemetryEndpoint, discriminator='OTLP'): + auth: TelemetryEndpointAuth + data: Union[list[str, TelemetryDataKind]] + endpoint: str + kind: Literal[TelemetryEndpointKind.OTLP] + protocol: Union[str, TelemetryTransportProtocol] + + @overload + def __init__( + self, + *, + auth: Optional[TelemetryEndpointAuth] = ..., + data: list[Union[str, TelemetryDataKind]], + endpoint: str, + protocol: Union[str, TelemetryTransportProtocol] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ScheduleTask(_Model): - configuration: Optional[dict[str, str]] - type: str + class azure.ai.projects.models.OutputTokensDetailsResource(_Model): + reasoning_tokens: int @overload def __init__( self, *, - configuration: Optional[dict[str, str]] = ..., - type: str + reasoning_tokens: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ScheduleTaskType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - EVALUATION = "Evaluation" - INSIGHT = "Insight" - - - class azure.ai.projects.models.SearchContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - IMAGE = "image" - TEXT = "text" - - - class azure.ai.projects.models.SearchContextSize(str, Enum, metaclass=CaseInsensitiveEnumMeta): - HIGH = "high" - LOW = "low" - MEDIUM = "medium" + class azure.ai.projects.models.PageOrder(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ASC = "asc" + DESC = "desc" - class azure.ai.projects.models.SessionConfiguration(_Model): - idle_timeout_seconds: Optional[timedelta] + class azure.ai.projects.models.PendingUploadRequest(_Model): + connection_name: Optional[str] + pending_upload_id: Optional[str] + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] @overload def __init__( self, *, - idle_timeout_seconds: Optional[timedelta] = ... + connection_name: Optional[str] = ..., + pending_upload_id: Optional[str] = ..., + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SessionDirectoryEntry(_Model): - is_directory: bool - modified_time: datetime - name: str - size: int + class azure.ai.projects.models.PendingUploadResponse(_Model): + blob_reference: BlobReference + pending_upload_id: str + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] + version: Optional[str] @overload def __init__( self, *, - is_directory: bool, - modified_time: datetime, - name: str, - size: int + blob_reference: BlobReference, + pending_upload_id: str, + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], + version: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SessionFileWriteResult(_Model): - bytes_written: int - path: str + class azure.ai.projects.models.PendingUploadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + BLOB_REFERENCE = "BlobReference" + NONE = "None" + TEMPORARY_BLOB_REFERENCE = "TemporaryBlobReference" + + + class azure.ai.projects.models.PerRecipientSchedule(TelephonyCampaignSchedule, discriminator='recipient'): + expires_at: datetime + type: Literal[TelephonyCampaignScheduleType.RECIPIENT] @overload def __init__( self, *, - bytes_written: int, - path: str + expires_at: Optional[datetime] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SessionLogEvent(_Model): - data: str - event: Union[str, SessionLogEventType] + class azure.ai.projects.models.PhoneNumber(TelephonyAddress, discriminator='phone_number'): + type: Literal[TelephonyAddressType.PHONE_NUMBER] + value: str @overload def __init__( self, *, - data: str, - event: Union[str, SessionLogEventType] + value: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SessionLogEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - LOG = "log" - - - class azure.ai.projects.models.SharepointGroundingToolParameters(_Model): - project_connections: Optional[list[ToolProjectConnection]] + class azure.ai.projects.models.PickPropertiesVoiceAgentAudioConfig(_Model): + output: Optional[VoiceAgentAudioOutputConfig] @overload def __init__( self, *, - project_connections: Optional[list[ToolProjectConnection]] = ... + output: Optional[VoiceAgentAudioOutputConfig] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SharepointPreviewTool(Tool, discriminator='sharepoint_grounding_preview'): - sharepoint_grounding_preview: SharepointGroundingToolParameters - type: Literal[ToolType.SHAREPOINT_GROUNDING_PREVIEW] + class azure.ai.projects.models.ProceduralMemoryItem(MemoryItem, discriminator='procedural'): + content: str + kind: Literal[MemoryItemKind.PROCEDURAL] + memory_id: str + scope: str + updated_at: datetime @overload def __init__( self, *, - sharepoint_grounding_preview: SharepointGroundingToolParameters + content: str, + memory_id: str, + scope: str, + updated_at: datetime ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ShellToolboxTool(ToolboxTool, discriminator='shell'): - allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] - description: str - environment: ToolboxShellEnvironment - name: str - tool_configs: dict[str, ToolConfig] - type: Literal[ToolboxToolType.SHELL] + class azure.ai.projects.models.ProgrammaticToolCallingParam(Tool, discriminator='programmatic_tool_calling'): + type: Literal[ToolType.PROGRAMMATIC_TOOL_CALLING] @overload - def __init__( - self, - *, - allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] = ..., - description: Optional[str] = ..., - environment: ToolboxShellEnvironment, - name: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ... - ) -> None: ... + def __init__(self) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SimpleQnADataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='simple_qna'): - max_samples: int - model_options: DataGenerationModelOptions - question_types: Optional[list[Union[str, SimpleQnAFineTuningQuestionType]]] - train_split: float - type: Literal[DataGenerationJobType.SIMPLE_QNA] + class azure.ai.projects.models.PromptAgentDefinition(AgentDefinition, discriminator='prompt'): + harness: Optional[AgentHarness] + instructions: Optional[str] + kind: Literal[AgentKind.PROMPT] + model: str + rai_config: RaiConfig + reasoning: Optional[Reasoning] + skills: Optional[list[SkillReference]] + structured_inputs: Optional[dict[str, StructuredInputDefinition]] + temperature: Optional[float] + text: Optional[PromptAgentDefinitionTextOptions] + tool_choice: Optional[Union[str, ToolChoiceParam]] + tools: Optional[list[Tool]] + top_p: Optional[float] @overload def __init__( self, *, - max_samples: int, - model_options: Optional[DataGenerationModelOptions] = ..., - question_types: Optional[list[Union[str, SimpleQnAFineTuningQuestionType]]] = ..., - train_split: Optional[float] = ... + harness: Optional[AgentHarness] = ..., + instructions: Optional[str] = ..., + model: str, + rai_config: Optional[RaiConfig] = ..., + reasoning: Optional[Reasoning] = ..., + skills: Optional[list[SkillReference]] = ..., + structured_inputs: Optional[dict[str, StructuredInputDefinition]] = ..., + temperature: Optional[float] = ..., + text: Optional[PromptAgentDefinitionTextOptions] = ..., + tool_choice: Optional[Union[str, ToolChoiceParam]] = ..., + tools: Optional[list[Tool]] = ..., + top_p: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SimpleQnAFineTuningQuestionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - LONG_ANSWER = "long_answer" - SHORT_ANSWER = "short_answer" - - - class azure.ai.projects.models.SimulationSeedDataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='simulation_seed'): - max_samples: int - model_options: DataGenerationModelOptions - train_split: float - type: Literal[DataGenerationJobType.SIMULATION_SEED] + class azure.ai.projects.models.PromptAgentDefinitionTextOptions(_Model): + format: Optional[TextResponseFormat] @overload def __init__( self, *, - max_samples: int, - model_options: Optional[DataGenerationModelOptions] = ..., - train_split: Optional[float] = ... + format: Optional[TextResponseFormat] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SipTelephonyTransferDestination(TelephonyTransferDestination, discriminator='sip'): - kind: Literal[TelephonyTransferDestinationKind.SIP] - value: str + class azure.ai.projects.models.PromptBasedEvaluatorDefinition(EvaluatorDefinition, discriminator='prompt'): + data_schema: dict[str, any] + init_parameters: dict[str, any] + metrics: dict[str, EvaluatorMetric] + prompt_text: str + type: Literal[EvaluatorDefinitionType.PROMPT] @overload def __init__( self, *, - value: str + data_schema: Optional[dict[str, Any]] = ..., + init_parameters: Optional[dict[str, Any]] = ..., + metrics: Optional[dict[str, EvaluatorMetric]] = ..., + prompt_text: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SkillDetails(_Model): - created_at: datetime - default_version: str + class azure.ai.projects.models.PromptDataGenerationJobSource(DataGenerationJobSource, discriminator='prompt'): description: str - id: str - latest_version: str - name: str + prompt: str + type: Literal[DataGenerationJobSourceType.PROMPT] @overload def __init__( self, *, - created_at: datetime, - default_version: str, - description: str, - id: str, - latest_version: str, - name: str + description: Optional[str] = ..., + prompt: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SkillInlineContent(_Model): - allowed_tools: Optional[list[str]] - compatibility: Optional[str] - description: str - instructions: str - license: Optional[str] - metadata: Optional[dict[str, str]] + class azure.ai.projects.models.PromptEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator='prompt'): + description: Optional[str] + prompt: str + type: Literal[EvaluatorGenerationJobSourceType.PROMPT] @overload def __init__( self, *, - allowed_tools: Optional[list[str]] = ..., - compatibility: Optional[str] = ..., - description: str, - instructions: str, - license: Optional[str] = ..., - metadata: Optional[dict[str, str]] = ... + description: Optional[str] = ..., + prompt: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SkillReference(_Model): - name: str - version: Optional[str] + class azure.ai.projects.models.PromptOptimizationConfiguration(AgentOptimizationConfigurationBase, discriminator='prompt_optimization'): + context: Optional[list[OptimizationContext]] + type: Literal[AgentOptimizationConfigurationType.PROMPT_OPTIMIZATION] @overload def __init__( self, *, - name: str, - version: Optional[str] = ... + context: Optional[list[OptimizationContext]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SkillReferenceParam(ContainerSkill, discriminator='skill_reference'): - skill_id: str - type: Literal[ContainerSkillType.SKILL_REFERENCE] - version: Optional[str] + class azure.ai.projects.models.ProtocolConfiguration(_Model): + a2a: Optional[A2AProtocolConfiguration] + activity: Optional[ActivityProtocolConfiguration] + invocations: Optional[InvocationsProtocolConfiguration] + invocations_ws: Optional[InvocationsWsProtocolConfiguration] + mcp: Optional[McpProtocolConfiguration] + responses: Optional[ResponsesProtocolConfiguration] @overload def __init__( self, *, - skill_id: str, - version: Optional[str] = ... - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + a2a: Optional[A2AProtocolConfiguration] = ..., + activity: Optional[ActivityProtocolConfiguration] = ..., + invocations: Optional[InvocationsProtocolConfiguration] = ..., + invocations_ws: Optional[InvocationsWsProtocolConfiguration] = ..., + mcp: Optional[McpProtocolConfiguration] = ..., + responses: Optional[ResponsesProtocolConfiguration] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SkillVersion(_Model): - created_at: datetime - description: str - id: str - name: str - skill_id: str + class azure.ai.projects.models.ProtocolVersionRecord(_Model): + protocol: Union[str, AgentEndpointProtocol] version: str @overload def __init__( self, *, - created_at: datetime, - description: str, - id: str, - name: str, - skill_id: str, + protocol: Union[str, AgentEndpointProtocol], version: str ) -> None: ... @@ -13158,547 +13225,3782 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SpecificApplyPatchParam(ToolChoiceParam, discriminator='apply_patch'): - type: Literal[ToolChoiceParamType.APPLY_PATCH] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.PublishApprovalStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + APPROVED = "approved" + NOT_PUBLISHED = "not_published" + NO_APPROVAL_NEEDED = "no_approval_needed" + PENDING = "pending" + REJECTED = "rejected" - class azure.ai.projects.models.SpecificFunctionShellParam(ToolChoiceParam, discriminator='shell'): - type: Literal[ToolChoiceParamType.SHELL] + class azure.ai.projects.models.RaiConfig(_Model): + invocations_moderation: Optional[RaiInvocationModeration] + rai_policy_name: str @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + invocations_moderation: Optional[RaiInvocationModeration] = ..., + rai_policy_name: str + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SpecificProgrammaticToolCallingParam(ToolChoiceParam, discriminator='programmatic_tool_calling'): - type: Literal[ToolChoiceParamType.PROGRAMMATIC_TOOL_CALLING] + class azure.ai.projects.models.RaiInvocationContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + JSON = "json" + TEXT = "text" - @overload - def __init__(self) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.RaiInvocationMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + BOTH = "both" + NON_STREAMING = "non_streaming" + STREAMING = "streaming" - class azure.ai.projects.models.SteeringPromptOptimizationContext(OptimizationContext, discriminator='steering_prompt'): - prompt: str - type: Literal[OptimizationContextType.STEERING_PROMPT] + class azure.ai.projects.models.RaiInvocationModeration(_Model): + input_content_type: Optional[Union[str, RaiInvocationContentType]] + input_paths: Optional[list[str]] + output_content_type: Optional[Union[str, RaiInvocationContentType]] + output_paths: Optional[list[str]] + response_mode: Union[str, RaiInvocationMode] + stream_selectors: Optional[list[RaiSseTextSelector]] @overload def __init__( self, *, - prompt: str + input_content_type: Optional[Union[str, RaiInvocationContentType]] = ..., + input_paths: Optional[list[str]] = ..., + output_content_type: Optional[Union[str, RaiInvocationContentType]] = ..., + output_paths: Optional[list[str]] = ..., + response_mode: Union[str, RaiInvocationMode], + stream_selectors: Optional[list[RaiSseTextSelector]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.StructuredInputDefinition(_Model): - default_value: Optional[Any] - description: Optional[str] - required: Optional[bool] - schema: Optional[dict[str, Any]] + class azure.ai.projects.models.RaiSseTextSelector(_Model): + event_type: str + text_field: Optional[str] @overload def __init__( self, *, - default_value: Optional[Any] = ..., - description: Optional[str] = ..., - required: Optional[bool] = ..., - schema: Optional[dict[str, Any]] = ... + event_type: str, + text_field: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.StructuredOutputDefinition(_Model): - description: str - name: str - schema: dict[str, Any] - strict: bool + class azure.ai.projects.models.RankerVersionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + DEFAULT_2024_11_15 = "default-2024-11-15" + + + class azure.ai.projects.models.RankingOptions(_Model): + hybrid_search: Optional[HybridSearchOptions] + ranker: Optional[Union[str, RankerVersionType]] + score_threshold: Optional[float] @overload def __init__( self, *, - description: str, - name: str, - schema: dict[str, Any], - strict: bool + hybrid_search: Optional[HybridSearchOptions] = ..., + ranker: Optional[Union[str, RankerVersionType]] = ..., + score_threshold: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SupervisedFineTuningDataGenerationJob(DataGenerationJob, discriminator='supervised_finetuning_preview'): - created_at: datetime - error: ApiError - finished_at: datetime - generation_configuration: DataGenerationJobConfiguration - id: str - name: str - output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] - result: DataGenerationJobResult - scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] - sources: list[DataGenerationJobSource] - status: Union[str, JobStatus] + class azure.ai.projects.models.RealtimeAudioFormats(_Model): + type: str @overload def __init__( self, *, - generation_configuration: DataGenerationJobConfiguration, - name: str, - output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] = ..., - sources: list[DataGenerationJobSource] + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SupervisedFineTuningDataGenerationJobInputs(DataGenerationJobInputs, discriminator='supervised_finetuning_preview'): - generation_configuration: DataGenerationJobConfiguration - name: str - output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] - scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] - sources: list[DataGenerationJobSource] + class azure.ai.projects.models.RealtimeAudioFormatsAudioPcm(RealtimeAudioFormats, discriminator='audio/pcm'): + rate: Optional[Literal[24000]] + type: Literal[RealtimeAudioFormatsType.AUDIO_PCM] @overload def __init__( self, *, - generation_configuration: DataGenerationJobConfiguration, - name: str, - output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] = ..., - sources: list[DataGenerationJobSource] + rate: Optional[Literal[24000]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration(_Model): - merge_file_id: Optional[str] - name: str - write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] + class azure.ai.projects.models.RealtimeAudioFormatsAudioPcma(RealtimeAudioFormats, discriminator='audio/pcma'): + type: Literal[RealtimeAudioFormatsType.AUDIO_PCMA] @overload - def __init__( - self, - *, - merge_file_id: Optional[str] = ..., - name: str, - write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] = ... - ) -> None: ... + def __init__(self) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TargetAttribute(str, Enum, metaclass=CaseInsensitiveEnumMeta): - INSTRUCTIONS = "instructions" - MODEL = "model" - SKILLS = "skills" - TOOLS = "tools" + class azure.ai.projects.models.RealtimeAudioFormatsAudioPcmu(RealtimeAudioFormats, discriminator='audio/pcmu'): + type: Literal[RealtimeAudioFormatsType.AUDIO_PCMU] + @overload + def __init__(self) -> None: ... - class azure.ai.projects.models.TargetCompletionEvalRunDataSource(TypedDict, total=False): - key "input_messages": Required[InputMessagesItemReference] - key "source": Required[Union[SourceFileContent, SourceFileID]] - key "target": Required[Union[AzureAIAgentTargetParam, AzureAIModelTargetParam, dict[str, Any]]] - key "type": Required[Literal["azure_ai_target_completions"]] + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TaxonomyCategory(_Model): - description: Optional[str] - id: str - name: str - properties: Optional[dict[str, str]] - risk_category: Union[str, RiskCategory] - sub_categories: list[TaxonomySubCategory] + class azure.ai.projects.models.RealtimeAudioFormatsType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUDIO_PCM = "audio/pcm" + AUDIO_PCMA = "audio/pcma" + AUDIO_PCMU = "audio/pcmu" + + + class azure.ai.projects.models.RealtimeClientEvent(_Model): + type: str @overload def __init__( self, *, - description: Optional[str] = ..., - id: str, - name: str, - properties: Optional[dict[str, str]] = ..., - risk_category: Union[str, RiskCategory], - sub_categories: list[TaxonomySubCategory] + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TaxonomySubCategory(_Model): - description: Optional[str] - enabled: bool - id: str - name: str - properties: Optional[dict[str, str]] + class azure.ai.projects.models.RealtimeClientEventConversationItemCreate(RealtimeClientEvent, discriminator='conversation.item.create'): + event_id: Optional[str] + item: RealtimeConversationItem + previous_item_id: Optional[str] + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_CREATE] @overload def __init__( self, *, - description: Optional[str] = ..., - enabled: bool, - id: str, - name: str, - properties: Optional[dict[str, str]] = ... + event_id: Optional[str] = ..., + item: RealtimeConversationItem, + previous_item_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TeamsPhoneExtensibilityTelephonyBinding(TelephonyBinding, discriminator='teams_phone_extensibility'): - connection_name: str - id: str - incoming_call_url: str - label: str - phone_number: Optional[str] - provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] - resource_account_object_id: str - status: Union[str, TelephonyBindingStatus] + class azure.ai.projects.models.RealtimeClientEventConversationItemDelete(RealtimeClientEvent, discriminator='conversation.item.delete'): + event_id: Optional[str] + item_id: str + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_DELETE] @overload def __init__( self, *, - connection_name: str, - id: str, - incoming_call_url: str, - label: Optional[str] = ..., - phone_number: Optional[str] = ..., - resource_account_object_id: str, - status: Union[str, TelephonyBindingStatus] + event_id: Optional[str] = ..., + item_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TeamsPhoneExtensibilityTelephonyBindingListItem(TelephonyBindingListItem, discriminator='teams_phone_extensibility'): - connection_name: str - etag: str - id: str - incoming_call_url: str - label: str - phone_number: Optional[str] - provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] - resource_account_object_id: str - status: Union[str, TelephonyBindingStatus] + class azure.ai.projects.models.RealtimeClientEventConversationItemRetrieve(RealtimeClientEvent, discriminator='conversation.item.retrieve'): + event_id: Optional[str] + item_id: str + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_RETRIEVE] @overload def __init__( self, *, - connection_name: str, - id: str, - incoming_call_url: str, - label: Optional[str] = ..., - phone_number: Optional[str] = ..., - resource_account_object_id: str, - status: Union[str, TelephonyBindingStatus] + event_id: Optional[str] = ..., + item_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TeamsTelephonyTransferDestination(TelephonyTransferDestination, discriminator='teams'): - kind: Literal[TelephonyTransferDestinationKind.TEAMS] - value: str + class azure.ai.projects.models.RealtimeClientEventConversationItemTruncate(RealtimeClientEvent, discriminator='conversation.item.truncate'): + audio_end_ms: int + content_index: int + event_id: Optional[str] + item_id: str + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_TRUNCATE] @overload def __init__( self, *, - value: str + audio_end_ms: int, + content_index: int, + event_id: Optional[str] = ..., + item_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelemetryConfig(_Model): - endpoints: list[TelemetryEndpoint] + class azure.ai.projects.models.RealtimeClientEventInputAudioBufferAppend(RealtimeClientEvent, discriminator='input_audio_buffer.append'): + audio: str + event_id: Optional[str] + type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_APPEND] @overload def __init__( self, *, - endpoints: list[TelemetryEndpoint] + audio: str, + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelemetryDataKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CONTAINER_OTEL = "ContainerOtel" - CONTAINER_STDOUT_STDERR = "ContainerStdoutStderr" - METRICS = "Metrics" - - - class azure.ai.projects.models.TelemetryEndpoint(_Model): - auth: Optional[TelemetryEndpointAuth] - data: list[Union[str, TelemetryDataKind]] - kind: str + class azure.ai.projects.models.RealtimeClientEventInputAudioBufferClear(RealtimeClientEvent, discriminator='input_audio_buffer.clear'): + event_id: Optional[str] + type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_CLEAR] @overload def __init__( self, *, - auth: Optional[TelemetryEndpointAuth] = ..., - data: list[Union[str, TelemetryDataKind]], - kind: str + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelemetryEndpointAuth(_Model): - type: str + class azure.ai.projects.models.RealtimeClientEventInputAudioBufferCommit(RealtimeClientEvent, discriminator='input_audio_buffer.commit'): + event_id: Optional[str] + type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_COMMIT] @overload def __init__( self, *, - type: str + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelemetryEndpointAuthType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - HEADER = "header" - - - class azure.ai.projects.models.TelemetryEndpointKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - OTLP = "OTLP" + class azure.ai.projects.models.RealtimeClientEventOutputAudioBufferClear(RealtimeClientEvent, discriminator='output_audio_buffer.clear'): + event_id: Optional[str] + type: Literal[RealtimeClientEventType.OUTPUT_AUDIO_BUFFER_CLEAR] + @overload + def __init__( + self, + *, + event_id: Optional[str] = ... + ) -> None: ... - class azure.ai.projects.models.TelemetryTransportProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): - GRPC = "Grpc" - HTTP = "Http" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyBinding(_Model): - connection_name: str - id: str - incoming_call_url: str - label: Optional[str] - provider: str - status: Union[str, TelephonyBindingStatus] + class azure.ai.projects.models.RealtimeClientEventResponseCancel(RealtimeClientEvent, discriminator='response.cancel'): + event_id: Optional[str] + response_id: Optional[str] + type: Literal[RealtimeClientEventType.RESPONSE_CANCEL] @overload def __init__( self, *, - connection_name: str, - id: str, - incoming_call_url: str, - label: Optional[str] = ..., - provider: str, - status: Union[str, TelephonyBindingStatus] + event_id: Optional[str] = ..., + response_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyBindingListItem(_Model): - connection_name: str - etag: str - id: str - incoming_call_url: str - label: Optional[str] - provider: str - status: Union[str, TelephonyBindingStatus] + class azure.ai.projects.models.RealtimeClientEventResponseCreate(RealtimeClientEvent, discriminator='response.create'): + event_id: Optional[str] + response: Optional[VoiceAgentResponseCreateParams] + type: Literal[RealtimeClientEventType.RESPONSE_CREATE] @overload def __init__( self, *, - connection_name: str, - id: str, - incoming_call_url: str, - label: Optional[str] = ..., - provider: str, - status: Union[str, TelephonyBindingStatus] + event_id: Optional[str] = ..., + response: Optional[VoiceAgentResponseCreateParams] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyBindingStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ACTIVE = "active" - SUSPENDED = "suspended" + class azure.ai.projects.models.RealtimeClientEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CONVERSATION_ITEM_CREATE = "conversation.item.create" + CONVERSATION_ITEM_DELETE = "conversation.item.delete" + CONVERSATION_ITEM_RETRIEVE = "conversation.item.retrieve" + CONVERSATION_ITEM_TRUNCATE = "conversation.item.truncate" + INPUT_AUDIO_BUFFER_APPEND = "input_audio_buffer.append" + INPUT_AUDIO_BUFFER_CLEAR = "input_audio_buffer.clear" + INPUT_AUDIO_BUFFER_COMMIT = "input_audio_buffer.commit" + OUTPUT_AUDIO_BUFFER_CLEAR = "output_audio_buffer.clear" + RESPONSE_CANCEL = "response.cancel" + RESPONSE_CREATE = "response.create" + RTC_CALL_SDP_CREATE = "rtc.call.sdp.create" + SESSION_AVATAR_CONNECT = "session.avatar.connect" + SESSION_UPDATE = "session.update" - class azure.ai.projects.models.TelephonyCallDurationBasis(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ANSWERED = "answered" - RECEIVED = "received" + class azure.ai.projects.models.RealtimeConversationItem(_Model): + type: str + @overload + def __init__( + self, + *, + type: str + ) -> None: ... - class azure.ai.projects.models.TelephonyCallEndReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ADMISSION_CHECK_FAILED = "admission_check_failed" - ADMISSION_REJECTED = "admission_rejected" - AGENT_SESSION_CONNECT_FAILED = "agent_session_connect_failed" - ANSWER_FAILED = "answer_failed" - BINDING_NOT_FOUND = "binding_not_found" - BINDING_SUSPENDED = "binding_suspended" - BRIDGE_CANCELLED = "bridge_cancelled" - BRIDGE_FAILED = "bridge_failed" - CREDENTIAL_RESOLUTION_FAILED = "credential_resolution_failed" - ENDPOINT_RESOLUTION_FAILED = "endpoint_resolution_failed" - INGRESS_SETUP_FAILED = "ingress_setup_failed" - INVALID_BINDING_CONFIGURATION = "invalid_binding_configuration" - INVALID_WEBHOOK_PAYLOAD = "invalid_webhook_payload" - LIVE_CALL_CONFLICT = "live_call_conflict" - LIVE_CALL_PERSISTENCE_FAILED = "live_call_persistence_failed" - MANAGED_HANGUP = "managed_hangup" - MANAGED_TRANSFER = "managed_transfer" - MANAGE_HANGUP_FAILED = "manage_hangup_failed" - MANAGE_TRANSFER_FAILED = "manage_transfer_failed" - MEDIA_STREAM_ENDED = "media_stream_ended" - PROVIDER_BUSY = "provider_busy" - PROVIDER_CANCELLED = "provider_cancelled" - PROVIDER_DISCONNECTED = "provider_disconnected" - PROVIDER_FAILED = "provider_failed" - PROVIDER_NO_ANSWER = "provider_no_answer" - PROVIDER_RESOURCE_MISMATCH = "provider_resource_mismatch" - PROVIDER_STREAM_ERROR = "provider_stream_error" - PROVIDER_STREAM_STOPPED = "provider_stream_stopped" - ROUTE_AGENT_MISMATCH = "route_agent_mismatch" - WEBHOOK_VALIDATION_FAILED = "webhook_validation_failed" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallJob(_Model): - agent_name: str - attempt_count: int - cancellation: Optional[TelephonyCallJobCancellation] - connection_name: str - created_at: datetime - destination: TelephonyOutboundDestination - id: str - next_attempt_at: Optional[datetime] - object: Literal["call_job"] - purpose: Optional[str] - retry_policy: TelephonyOutboundRetryPolicy - revision: int - schedule: Optional[TelephonyCallJobSchedule] - source: str - status: Union[str, TelephonyCallJobStatus] - structured_inputs: Optional[dict[str, Any]] - terminal_reason: Optional[Union[str, TelephonyCallJobTerminalReason]] - updated_at: datetime + class azure.ai.projects.models.RealtimeConversationItemFunctionCall(RealtimeConversationItem, discriminator='function_call'): + arguments: str + call_id: Optional[str] + created_at: Optional[datetime] + id: Optional[str] + name: str + object: Optional[Literal["item"]] + response_id: Optional[str] + status: Optional[Literal["completed", "incomplete", "in_progress"]] + type: Literal[RealtimeConversationItemType.FUNCTION_CALL] @overload def __init__( self, *, - agent_name: str, - attempt_count: int, - cancellation: Optional[TelephonyCallJobCancellation] = ..., - connection_name: str, - created_at: datetime, - destination: TelephonyOutboundDestination, - id: str, - next_attempt_at: Optional[datetime] = ..., - purpose: Optional[str] = ..., - retry_policy: TelephonyOutboundRetryPolicy, - revision: int, - schedule: Optional[TelephonyCallJobSchedule] = ..., - source: str, - status: Union[str, TelephonyCallJobStatus], - structured_inputs: Optional[dict[str, Any]] = ..., - terminal_reason: Optional[Union[str, TelephonyCallJobTerminalReason]] = ..., - updated_at: datetime + arguments: str, + call_id: Optional[str] = ..., + id: Optional[str] = ..., + name: str, + object: Optional[Literal[item]] = ..., + status: Optional[Literal[completed, incomplete, in_progress]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallJobCancellation(_Model): - mode: str - requested_at: datetime - requested_by: str - revision: int + class azure.ai.projects.models.RealtimeConversationItemFunctionCallOutput(RealtimeConversationItem, discriminator='function_call_output'): + call_id: str + created_at: Optional[datetime] + id: Optional[str] + name: Optional[str] + object: Optional[Literal["item"]] + output: str + response_id: Optional[str] + status: Optional[Literal["completed", "incomplete", "in_progress"]] + type: Literal[RealtimeConversationItemType.FUNCTION_CALL_OUTPUT] @overload def __init__( self, *, - mode: str, - requested_at: datetime, - requested_by: str, - revision: int + call_id: str, + id: Optional[str] = ..., + name: Optional[str] = ..., + object: Optional[Literal[item]] = ..., + output: str, + status: Optional[Literal[completed, incomplete, in_progress]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallJobSchedule(_Model): - expires_at: Optional[datetime] - not_before: Optional[datetime] + class azure.ai.projects.models.RealtimeConversationItemMessage(RealtimeConversationItem, discriminator='message'): + role: str + type: Literal[RealtimeConversationItemType.MESSAGE] @overload def __init__( self, *, - expires_at: Optional[datetime] = ..., - not_before: Optional[datetime] = ... + role: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallJobStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ACCEPTED = "accepted" - BLOCKED = "blocked" - CANCELLATION_REQUESTED = "cancellation_requested" - CANCELLED = "cancelled" - COMPLETED = "completed" - DISPATCHING = "dispatching" - EXPIRED = "expired" - FAILED = "failed" - IN_PROGRESS = "in_progress" - QUEUED = "queued" - WAITING_FOR_RETRY = "waiting_for_retry" - WAITING_FOR_SCHEDULE = "waiting_for_schedule" - - - class azure.ai.projects.models.TelephonyCallJobTerminalReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ANSWER_FAILED = "answer_failed" - BRIDGE_CANCELLED = "bridge_cancelled" - BRIDGE_FAILED = "bridge_failed" - CAMPAIGN_CANCELLED = "campaign_cancelled" + class azure.ai.projects.models.RealtimeConversationItemMessageAssistant(RealtimeConversationItemMessage, discriminator='assistant'): + content: list[RealtimeConversationItemMessageAssistantContent] + created_at: Optional[datetime] + id: Optional[str] + object: Optional[Literal["item"]] + response_id: Optional[str] + role: Literal[RealtimeConversationItemMessageType.ASSISTANT] + status: Optional[Literal["completed", "incomplete", "in_progress"]] + type: Union[str, azure.ai.projects.models.MESSAGE] + + @overload + def __init__( + self, + *, + content: list[RealtimeConversationItemMessageAssistantContent], + id: Optional[str] = ..., + object: Optional[Literal[item]] = ..., + status: Optional[Literal[completed, incomplete, in_progress]] = ..., + type: Literal[RealtimeConversationItemType.MESSAGE] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeConversationItemMessageAssistantContent(_Model): + audio: Optional[str] + text: Optional[str] + transcript: Optional[str] + type: Optional[Literal["output_text", "output_audio"]] + + @overload + def __init__( + self, + *, + audio: Optional[str] = ..., + text: Optional[str] = ..., + transcript: Optional[str] = ..., + type: Optional[Literal[output_text, output_audio]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeConversationItemMessageSystem(RealtimeConversationItemMessage, discriminator='system'): + content: list[RealtimeConversationItemMessageSystemContent] + created_at: Optional[datetime] + id: Optional[str] + object: Optional[Literal["item"]] + response_id: Optional[str] + role: Literal[RealtimeConversationItemMessageType.SYSTEM] + status: Optional[Literal["completed", "incomplete", "in_progress"]] + type: Union[str, azure.ai.projects.models.MESSAGE] + + @overload + def __init__( + self, + *, + content: list[RealtimeConversationItemMessageSystemContent], + id: Optional[str] = ..., + object: Optional[Literal[item]] = ..., + status: Optional[Literal[completed, incomplete, in_progress]] = ..., + type: Literal[RealtimeConversationItemType.MESSAGE] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeConversationItemMessageSystemContent(_Model): + text: Optional[str] + type: Optional[Literal["input_text"]] + + @overload + def __init__( + self, + *, + text: Optional[str] = ..., + type: Optional[Literal[input_text]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeConversationItemMessageType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ASSISTANT = "assistant" + SYSTEM = "system" + USER = "user" + + + class azure.ai.projects.models.RealtimeConversationItemMessageUser(RealtimeConversationItemMessage, discriminator='user'): + content: list[RealtimeConversationItemMessageUserContent] + created_at: Optional[datetime] + id: Optional[str] + object: Optional[Literal["item"]] + response_id: Optional[str] + role: Literal[RealtimeConversationItemMessageType.USER] + status: Optional[Literal["completed", "incomplete", "in_progress"]] + type: Union[str, azure.ai.projects.models.MESSAGE] + + @overload + def __init__( + self, + *, + content: list[RealtimeConversationItemMessageUserContent], + id: Optional[str] = ..., + object: Optional[Literal[item]] = ..., + status: Optional[Literal[completed, incomplete, in_progress]] = ..., + type: Literal[RealtimeConversationItemType.MESSAGE] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeConversationItemMessageUserContent(_Model): + audio: Optional[str] + detail: Optional[Literal["auto", "low", "high"]] + image_url: Optional[str] + text: Optional[str] + transcript: Optional[str] + type: Optional[Literal["input_text", "input_audio", "input_image"]] + + @overload + def __init__( + self, + *, + audio: Optional[str] = ..., + detail: Optional[Literal[auto, low, high]] = ..., + image_url: Optional[str] = ..., + text: Optional[str] = ..., + transcript: Optional[str] = ..., + type: Optional[Literal[input_text, input_audio, input_image]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeConversationItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FUNCTION_CALL = "function_call" + FUNCTION_CALL_OUTPUT = "function_call_output" + MCP_APPROVAL_REQUEST = "mcp_approval_request" + MCP_APPROVAL_RESPONSE = "mcp_approval_response" + MCP_CALL = "mcp_call" + MCP_LIST_TOOLS = "mcp_list_tools" + MESSAGE = "message" + SYSTEM_TOOL = "system_tool" + + + class azure.ai.projects.models.RealtimeFunctionTool(_Model): + description: Optional[str] + name: Optional[str] + parameters: Optional[RealtimeFunctionToolParameters] + type: Optional[Literal["function"]] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + name: Optional[str] = ..., + parameters: Optional[RealtimeFunctionToolParameters] = ..., + type: Optional[Literal[function]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeFunctionToolParameters(_Model): + + + class azure.ai.projects.models.RealtimeMCPApprovalRequest(RealtimeConversationItem, discriminator='mcp_approval_request'): + arguments: str + created_at: Optional[datetime] + id: str + name: str + response_id: Optional[str] + server_label: str + type: Literal[RealtimeConversationItemType.MCP_APPROVAL_REQUEST] + + @overload + def __init__( + self, + *, + arguments: str, + id: str, + name: str, + server_label: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPApprovalResponse(RealtimeConversationItem, discriminator='mcp_approval_response'): + approval_request_id: str + approve: bool + created_at: Optional[datetime] + id: str + reason: Optional[str] + response_id: Optional[str] + type: Literal[RealtimeConversationItemType.MCP_APPROVAL_RESPONSE] + + @overload + def __init__( + self, + *, + approval_request_id: str, + approve: bool, + id: str, + reason: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPError(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPHTTPError(RealtimeMCPError, discriminator='http_error'): + code: int + message: str + type: Literal[RealtimeMcpErrorType.HTTP_ERROR] + + @overload + def __init__( + self, + *, + code: int, + message: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPListTools(RealtimeConversationItem, discriminator='mcp_list_tools'): + created_at: Optional[datetime] + id: Optional[str] + response_id: Optional[str] + server_label: str + tools: list[MCPListToolsTool] + type: Literal[RealtimeConversationItemType.MCP_LIST_TOOLS] + + @overload + def __init__( + self, + *, + id: Optional[str] = ..., + server_label: str, + tools: list[MCPListToolsTool] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPProtocolError(RealtimeMCPError, discriminator='protocol_error'): + code: int + message: str + type: Literal[RealtimeMcpErrorType.PROTOCOL_ERROR] + + @overload + def __init__( + self, + *, + code: int, + message: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPToolCall(RealtimeConversationItem, discriminator='mcp_call'): + approval_request_id: Optional[str] + arguments: str + created_at: Optional[datetime] + error: Optional[RealtimeMCPError] + id: str + name: str + output: Optional[str] + response_id: Optional[str] + server_label: str + type: Literal[RealtimeConversationItemType.MCP_CALL] + + @overload + def __init__( + self, + *, + approval_request_id: Optional[str] = ..., + arguments: str, + error: Optional[RealtimeMCPError] = ..., + id: str, + name: str, + output: Optional[str] = ..., + server_label: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMCPToolExecutionError(RealtimeMCPError, discriminator='tool_execution_error'): + message: str + type: Literal[RealtimeMcpErrorType.TOOL_EXECUTION_ERROR] + + @overload + def __init__( + self, + *, + message: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeMcpErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HTTP_ERROR = "http_error" + PROTOCOL_ERROR = "protocol_error" + TOOL_EXECUTION_ERROR = "tool_execution_error" + + + class azure.ai.projects.models.RealtimeReasoning(_Model): + effort: Optional[Union[str, RealtimeReasoningEffort]] + + @overload + def __init__( + self, + *, + effort: Optional[Union[str, RealtimeReasoningEffort]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + MEDIUM = "medium" + MINIMAL = "minimal" + XHIGH = "xhigh" + + + class azure.ai.projects.models.RealtimeResponseInputAudio(_Model): + audio: str + transcript: Optional[str] + type: Literal["input_audio"] + + @overload + def __init__( + self, + *, + audio: str, + transcript: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputFunctionCall(_Model): + arguments: str + call_id: str + id: Optional[str] + name: str + status: Optional[Literal["completed", "incomplete"]] + type: Literal["function_call"] + + @overload + def __init__( + self, + *, + arguments: str, + call_id: str, + id: Optional[str] = ..., + name: str, + status: Optional[Literal[completed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputFunctionCallOutput(_Model): + call_id: str + id: Optional[str] + output: str + status: Optional[Literal["completed", "incomplete"]] + type: Literal["function_call_output"] + + @overload + def __init__( + self, + *, + call_id: str, + id: Optional[str] = ..., + output: str, + status: Optional[Literal[completed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputImage(_Model): + detail: Optional[Literal["auto", "low", "high"]] + image_url: str + type: Literal["input_image"] + + @overload + def __init__( + self, + *, + detail: Optional[Literal[low, high, auto]] = ..., + image_url: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputMessage(_Model): + role: str + + @overload + def __init__( + self, + *, + role: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputMessageAssistant(RealtimeResponseInputMessage, discriminator='assistant'): + content: list[RealtimeResponseInputMessageAssistantContent] + id: Optional[str] + role: Literal[RealtimeResponseInputMessageType.ASSISTANT] + status: Optional[Literal["completed", "incomplete"]] + type: Literal["message"] + + @overload + def __init__( + self, + *, + content: list[RealtimeResponseInputMessageAssistantContent], + id: Optional[str] = ..., + status: Optional[Literal[completed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputMessageAssistantContent(_Model): + text: str + type: Literal["output_text"] + + @overload + def __init__( + self, + *, + text: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputMessageDeveloper(RealtimeResponseInputMessage, discriminator='developer'): + content: list[RealtimeResponseInputText] + id: Optional[str] + role: Literal[RealtimeResponseInputMessageType.DEVELOPER] + status: Optional[Literal["completed", "incomplete"]] + type: Literal["message"] + + @overload + def __init__( + self, + *, + content: list[RealtimeResponseInputText], + id: Optional[str] = ..., + status: Optional[Literal[completed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputMessageSystem(RealtimeResponseInputMessage, discriminator='system'): + content: list[RealtimeResponseInputText] + id: Optional[str] + role: Literal[RealtimeResponseInputMessageType.SYSTEM] + status: Optional[Literal["completed", "incomplete"]] + type: Literal["message"] + + @overload + def __init__( + self, + *, + content: list[RealtimeResponseInputText], + id: Optional[str] = ..., + status: Optional[Literal[completed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputMessageType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ASSISTANT = "assistant" + DEVELOPER = "developer" + SYSTEM = "system" + USER = "user" + + + class azure.ai.projects.models.RealtimeResponseInputMessageUser(RealtimeResponseInputMessage, discriminator='user'): + content: list[Union[RealtimeResponseInputText, RealtimeResponseInputAudio, RealtimeResponseInputImage]] + id: Optional[str] + role: Literal[RealtimeResponseInputMessageType.USER] + status: Optional[Literal["completed", "incomplete"]] + type: Literal["message"] + + @overload + def __init__( + self, + *, + content: list[Union[RealtimeResponseInputText, RealtimeResponseInputAudio, RealtimeResponseInputImage]], + id: Optional[str] = ..., + status: Optional[Literal[completed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseInputText(_Model): + text: str + type: Literal["input_text"] + + @overload + def __init__( + self, + *, + text: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseItemReference(_Model): + id: str + type: Literal["item_reference"] + + @overload + def __init__( + self, + *, + id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseStatusDetails(_Model): + error: Optional[RealtimeResponseStatusDetailsError] + reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] + type: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] + + @overload + def __init__( + self, + *, + error: Optional[RealtimeResponseStatusDetailsError] = ..., + reason: Optional[Literal[turn_detected, client_cancelled, max_output_tokens, content_filter]] = ..., + type: Optional[Literal[completed, cancelled, failed, incomplete]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseStatusDetailsError(_Model): + code: Optional[str] + message: Optional[str] + type: Optional[str] + + @overload + def __init__( + self, + *, + code: Optional[str] = ..., + message: Optional[str] = ..., + type: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseUsage(_Model): + input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] + input_tokens: Optional[int] + output_token_details: Optional[RealtimeResponseUsageOutputTokenDetails] + output_tokens: Optional[int] + total_tokens: Optional[int] + + @overload + def __init__( + self, + *, + input_token_details: Optional[RealtimeResponseUsageInputTokenDetails] = ..., + input_tokens: Optional[int] = ..., + output_token_details: Optional[RealtimeResponseUsageOutputTokenDetails] = ..., + output_tokens: Optional[int] = ..., + total_tokens: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseUsageInputTokenDetails(_Model): + audio_tokens: Optional[int] + cached_tokens: Optional[int] + cached_tokens_details: Optional[RealtimeResponseUsageInputTokenDetailsCachedTokensDetails] + image_tokens: Optional[int] + text_tokens: Optional[int] + + @overload + def __init__( + self, + *, + audio_tokens: Optional[int] = ..., + cached_tokens: Optional[int] = ..., + cached_tokens_details: Optional[RealtimeResponseUsageInputTokenDetailsCachedTokensDetails] = ..., + image_tokens: Optional[int] = ..., + text_tokens: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails(_Model): + audio_tokens: Optional[int] + image_tokens: Optional[int] + text_tokens: Optional[int] + + @overload + def __init__( + self, + *, + audio_tokens: Optional[int] = ..., + image_tokens: Optional[int] = ..., + text_tokens: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeResponseUsageOutputTokenDetails(_Model): + audio_tokens: Optional[int] + text_tokens: Optional[int] + + @overload + def __init__( + self, + *, + audio_tokens: Optional[int] = ..., + text_tokens: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEvent(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemAdded(RealtimeServerEvent, discriminator='conversation.item.added'): + event_id: str + item: RealtimeConversationItem + previous_item_id: Optional[str] + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_ADDED] + + @overload + def __init__( + self, + *, + event_id: str, + item: RealtimeConversationItem, + previous_item_id: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemCreated(RealtimeServerEvent, discriminator='conversation.item.created'): + event_id: str + item: RealtimeConversationItem + previous_item_id: Optional[str] + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_CREATED] + + @overload + def __init__( + self, + *, + event_id: str, + item: RealtimeConversationItem, + previous_item_id: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemDeleted(RealtimeServerEvent, discriminator='conversation.item.deleted'): + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DELETED] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemDone(RealtimeServerEvent, discriminator='conversation.item.done'): + event_id: str + item: RealtimeConversationItem + previous_item_id: Optional[str] + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DONE] + + @overload + def __init__( + self, + *, + event_id: str, + item: RealtimeConversationItem, + previous_item_id: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionCompleted(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.completed'): + content_index: int + event_id: str + item_id: str + languages: Optional[list[TranscriptionLanguage]] + logprobs: Optional[list[LogProbProperties]] + phrases: Optional[list[VoiceAgentTranscriptionPhrase]] + transcript: str + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED] + usage: Union[TranscriptTextUsageTokens, TranscriptTextUsageDuration] + + @overload + def __init__( + self, + *, + content_index: int, + event_id: str, + item_id: str, + languages: Optional[list[TranscriptionLanguage]] = ..., + logprobs: Optional[list[LogProbProperties]] = ..., + phrases: Optional[list[VoiceAgentTranscriptionPhrase]] = ..., + transcript: str, + usage: Union[TranscriptTextUsageTokens, TranscriptTextUsageDuration] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionDelta(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.delta'): + content_index: Optional[int] + delta: Optional[str] + event_id: str + item_id: str + logprobs: Optional[list[LogProbProperties]] + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA] + + @overload + def __init__( + self, + *, + content_index: Optional[int] = ..., + delta: Optional[str] = ..., + event_id: str, + item_id: str, + logprobs: Optional[list[LogProbProperties]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionFailed(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.failed'): + content_index: int + error: RealtimeServerEventConversationItemInputAudioTranscriptionFailedError + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED] + + @overload + def __init__( + self, + *, + content_index: int, + error: RealtimeServerEventConversationItemInputAudioTranscriptionFailedError, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError(_Model): + code: Optional[str] + message: Optional[str] + param: Optional[str] + type: Optional[str] + + @overload + def __init__( + self, + *, + code: Optional[str] = ..., + message: Optional[str] = ..., + param: Optional[str] = ..., + type: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionSegment(RealtimeServerEvent, discriminator='conversation.item.input_audio_transcription.segment'): + content_index: int + end: float + event_id: str + id: str + item_id: str + speaker: str + start: float + text: str + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT] + + @overload + def __init__( + self, + *, + content_index: int, + end: float, + event_id: str, + id: str, + item_id: str, + speaker: str, + start: float, + text: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemRetrieved(RealtimeServerEvent, discriminator='conversation.item.retrieved'): + event_id: str + item: RealtimeConversationItem + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_RETRIEVED] + + @overload + def __init__( + self, + *, + event_id: str, + item: RealtimeConversationItem + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventConversationItemTruncated(RealtimeServerEvent, discriminator='conversation.item.truncated'): + audio_end_ms: int + content_index: int + event_id: str + item: Optional[RealtimeConversationItem] + item_id: str + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_TRUNCATED] + + @overload + def __init__( + self, + *, + audio_end_ms: int, + content_index: int, + event_id: str, + item: Optional[RealtimeConversationItem] = ..., + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventError(_Model): + error: RealtimeServerEventErrorError + event_id: str + type: Literal["error"] + + @overload + def __init__( + self, + *, + error: RealtimeServerEventErrorError, + event_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventErrorError(_Model): + code: Optional[str] + event_id: Optional[str] + message: str + param: Optional[str] + type: str + + @overload + def __init__( + self, + *, + code: Optional[str] = ..., + event_id: Optional[str] = ..., + message: str, + param: Optional[str] = ..., + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventInputAudioBufferCleared(RealtimeServerEvent, discriminator='input_audio_buffer.cleared'): + event_id: str + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_CLEARED] + + @overload + def __init__( + self, + *, + event_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventInputAudioBufferCommitted(RealtimeServerEvent, discriminator='input_audio_buffer.committed'): + event_id: str + item_id: str + previous_item_id: Optional[str] + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_COMMITTED] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + previous_item_id: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventInputAudioBufferSpeechStarted(RealtimeServerEvent, discriminator='input_audio_buffer.speech_started'): + audio_start_ms: int + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED] + + @overload + def __init__( + self, + *, + audio_start_ms: int, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventInputAudioBufferSpeechStopped(RealtimeServerEvent, discriminator='input_audio_buffer.speech_stopped'): + audio_end_ms: int + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STOPPED] + + @overload + def __init__( + self, + *, + audio_end_ms: int, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventInputAudioBufferTimeoutTriggered(RealtimeServerEvent, discriminator='input_audio_buffer.timeout_triggered'): + audio_end_ms: int + audio_start_ms: int + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED] + + @overload + def __init__( + self, + *, + audio_end_ms: int, + audio_start_ms: int, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventMCPListToolsCompleted(RealtimeServerEvent, discriminator='mcp_list_tools.completed'): + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_COMPLETED] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventMCPListToolsFailed(RealtimeServerEvent, discriminator='mcp_list_tools.failed'): + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_FAILED] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventMCPListToolsInProgress(RealtimeServerEvent, discriminator='mcp_list_tools.in_progress'): + event_id: str + item_id: str + type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_IN_PROGRESS] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventOutputAudioBufferCleared(RealtimeServerEvent, discriminator='output_audio_buffer.cleared'): + event_id: str + response_id: str + type: Literal[RealtimeServerEventType.OUTPUT_AUDIO_BUFFER_CLEARED] + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventRateLimitsUpdated(RealtimeServerEvent, discriminator='rate_limits.updated'): + event_id: str + rate_limits: list[RealtimeServerEventRateLimitsUpdatedRateLimits] + type: Literal[RealtimeServerEventType.RATE_LIMITS_UPDATED] + + @overload + def __init__( + self, + *, + event_id: str, + rate_limits: list[RealtimeServerEventRateLimitsUpdatedRateLimits] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventRateLimitsUpdatedRateLimits(_Model): + limit: Optional[int] + name: Optional[Literal["requests", "tokens"]] + remaining: Optional[int] + reset_seconds: Optional[float] + + @overload + def __init__( + self, + *, + limit: Optional[int] = ..., + name: Optional[Literal[requests, tokens]] = ..., + remaining: Optional[int] = ..., + reset_seconds: Optional[float] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseAudioDelta(RealtimeServerEvent, discriminator='response.output_audio.delta'): + content_index: int + delta: bytes + event_id: str + item_id: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DELTA] + + @overload + def __init__( + self, + *, + content_index: int, + delta: bytes, + event_id: str, + item_id: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseAudioDone(RealtimeServerEvent, discriminator='response.output_audio.done'): + content_index: int + event_id: str + item_id: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DONE] + + @overload + def __init__( + self, + *, + content_index: int, + event_id: str, + item_id: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseAudioTranscriptDelta(RealtimeServerEvent, discriminator='response.output_audio_transcript.delta'): + content_index: int + delta: str + event_id: str + item_id: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA] + + @overload + def __init__( + self, + *, + content_index: int, + delta: str, + event_id: str, + item_id: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseAudioTranscriptDone(RealtimeServerEvent, discriminator='response.output_audio_transcript.done'): + content_index: int + event_id: str + item_id: str + output_index: int + response_id: str + transcript: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE] + + @overload + def __init__( + self, + *, + content_index: int, + event_id: str, + item_id: str, + output_index: int, + response_id: str, + transcript: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseContentPartAdded(RealtimeServerEvent, discriminator='response.content_part.added'): + content_index: int + event_id: str + item_id: str + output_index: int + part: RealtimeServerEventResponseContentPartAddedPart + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_ADDED] + + @overload + def __init__( + self, + *, + content_index: int, + event_id: str, + item_id: str, + output_index: int, + part: RealtimeServerEventResponseContentPartAddedPart, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseContentPartAddedPart(_Model): + audio: Optional[str] + text: Optional[str] + transcript: Optional[str] + type: Optional[Literal["audio", "text"]] + + @overload + def __init__( + self, + *, + audio: Optional[str] = ..., + text: Optional[str] = ..., + transcript: Optional[str] = ..., + type: Optional[Literal[audio, text]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseContentPartDone(RealtimeServerEvent, discriminator='response.content_part.done'): + content_index: int + event_id: str + item_id: str + output_index: int + part: RealtimeServerEventResponseContentPartDonePart + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_DONE] + + @overload + def __init__( + self, + *, + content_index: int, + event_id: str, + item_id: str, + output_index: int, + part: RealtimeServerEventResponseContentPartDonePart, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseContentPartDonePart(_Model): + audio: Optional[str] + format: Optional[RealtimeAudioFormats] + text: Optional[str] + transcript: Optional[str] + type: Optional[Literal["audio", "text"]] + + @overload + def __init__( + self, + *, + audio: Optional[str] = ..., + format: Optional[RealtimeAudioFormats] = ..., + text: Optional[str] = ..., + transcript: Optional[str] = ..., + type: Optional[Literal[audio, text]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseCreated(RealtimeServerEvent, discriminator='response.created'): + event_id: str + response: VoiceAgentRealtimeResponse + type: Literal[RealtimeServerEventType.RESPONSE_CREATED] + + @overload + def __init__( + self, + *, + event_id: str, + response: VoiceAgentRealtimeResponse + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseDone(RealtimeServerEvent, discriminator='response.done'): + event_id: str + response: VoiceAgentRealtimeResponse + type: Literal[RealtimeServerEventType.RESPONSE_DONE] + + @overload + def __init__( + self, + *, + event_id: str, + response: VoiceAgentRealtimeResponse + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseFunctionCallArgumentsDelta(RealtimeServerEvent, discriminator='response.function_call_arguments.delta'): + call_id: str + delta: str + event_id: str + item_id: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA] + + @overload + def __init__( + self, + *, + call_id: str, + delta: str, + event_id: str, + item_id: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseFunctionCallArgumentsDone(RealtimeServerEvent, discriminator='response.function_call_arguments.done'): + arguments: str + call_id: str + event_id: str + item_id: str + name: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE] + + @overload + def __init__( + self, + *, + arguments: str, + call_id: str, + event_id: str, + item_id: str, + name: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseMCPCallArgumentsDelta(RealtimeServerEvent, discriminator='response.mcp_call_arguments.delta'): + delta: str + event_id: str + item_id: str + obfuscation: Optional[str] + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DELTA] + + @overload + def __init__( + self, + *, + delta: str, + event_id: str, + item_id: str, + obfuscation: Optional[str] = ..., + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseMCPCallArgumentsDone(RealtimeServerEvent, discriminator='response.mcp_call_arguments.done'): + arguments: str + event_id: str + item_id: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DONE] + + @overload + def __init__( + self, + *, + arguments: str, + event_id: str, + item_id: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseMCPCallCompleted(RealtimeServerEvent, discriminator='response.mcp_call.completed'): + event_id: str + item_id: str + output_index: int + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_COMPLETED] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + output_index: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseMCPCallFailed(RealtimeServerEvent, discriminator='response.mcp_call.failed'): + event_id: str + item_id: str + output_index: int + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_FAILED] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + output_index: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseMCPCallInProgress(RealtimeServerEvent, discriminator='response.mcp_call.in_progress'): + event_id: str + item_id: str + output_index: int + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_IN_PROGRESS] + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + output_index: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseOutputItemAdded(RealtimeServerEvent, discriminator='response.output_item.added'): + event_id: str + item: RealtimeConversationItem + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_ADDED] + + @overload + def __init__( + self, + *, + event_id: str, + item: RealtimeConversationItem, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseOutputItemDone(RealtimeServerEvent, discriminator='response.output_item.done'): + event_id: str + item: RealtimeConversationItem + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_DONE] + + @overload + def __init__( + self, + *, + event_id: str, + item: RealtimeConversationItem, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseTextDelta(RealtimeServerEvent, discriminator='response.output_text.delta'): + content_index: int + delta: str + event_id: str + item_id: str + output_index: int + response_id: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DELTA] + + @overload + def __init__( + self, + *, + content_index: int, + delta: str, + event_id: str, + item_id: str, + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventResponseTextDone(RealtimeServerEvent, discriminator='response.output_text.done'): + content_index: int + event_id: str + item_id: str + output_index: int + response_id: str + text: str + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DONE] + + @overload + def __init__( + self, + *, + content_index: int, + event_id: str, + item_id: str, + output_index: int, + response_id: str, + text: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventSessionCreated(RealtimeServerEvent, discriminator='session.created'): + conversation_id: Optional[str] + event_id: str + session: VoiceAgentSessionResponse + type: Literal[RealtimeServerEventType.SESSION_CREATED] + + @overload + def __init__( + self, + *, + conversation_id: Optional[str] = ..., + event_id: str, + session: VoiceAgentSessionResponse + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventSessionUpdated(RealtimeServerEvent, discriminator='session.updated'): + event_id: str + session: VoiceAgentSessionResponse + type: Literal[RealtimeServerEventType.SESSION_UPDATED] + + @overload + def __init__( + self, + *, + event_id: str, + session: VoiceAgentSessionResponse + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RealtimeServerEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CONVERSATION_CREATED = "conversation.created" + CONVERSATION_ITEM_ADDED = "conversation.item.added" + CONVERSATION_ITEM_CREATED = "conversation.item.created" + CONVERSATION_ITEM_DELETED = "conversation.item.deleted" + CONVERSATION_ITEM_DONE = "conversation.item.done" + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED = "conversation.item.input_audio_transcription.completed" + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA = "conversation.item.input_audio_transcription.delta" + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED = "conversation.item.input_audio_transcription.failed" + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT = "conversation.item.input_audio_transcription.segment" + CONVERSATION_ITEM_RETRIEVED = "conversation.item.retrieved" + CONVERSATION_ITEM_TRUNCATED = "conversation.item.truncated" + ERROR = "error" + INPUT_AUDIO_BUFFER_CLEARED = "input_audio_buffer.cleared" + INPUT_AUDIO_BUFFER_COMMITTED = "input_audio_buffer.committed" + INPUT_AUDIO_BUFFER_DTMF_EVENT_RECEIVED = "input_audio_buffer.dtmf_event_received" + INPUT_AUDIO_BUFFER_SPEECH_STARTED = "input_audio_buffer.speech_started" + INPUT_AUDIO_BUFFER_SPEECH_STOPPED = "input_audio_buffer.speech_stopped" + INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED = "input_audio_buffer.timeout_triggered" + INPUT_COLLECTION_STATUS = "input_collection.status" + MCP_LIST_TOOLS_COMPLETED = "mcp_list_tools.completed" + MCP_LIST_TOOLS_FAILED = "mcp_list_tools.failed" + MCP_LIST_TOOLS_IN_PROGRESS = "mcp_list_tools.in_progress" + OUTPUT_AUDIO_BUFFER_CLEARED = "output_audio_buffer.cleared" + OUTPUT_AUDIO_BUFFER_STARTED = "output_audio_buffer.started" + OUTPUT_AUDIO_BUFFER_STOPPED = "output_audio_buffer.stopped" + RATE_LIMITS_UPDATED = "rate_limits.updated" + RESPONSE_ANIMATION_BLENDSHAPES_DELTA = "response.animation_blendshapes.delta" + RESPONSE_ANIMATION_BLENDSHAPES_DONE = "response.animation_blendshapes.done" + RESPONSE_ANIMATION_VISEME_DELTA = "response.animation_viseme.delta" + RESPONSE_ANIMATION_VISEME_DONE = "response.animation_viseme.done" + RESPONSE_AUDIO_TIMESTAMP_DELTA = "response.audio_timestamp.delta" + RESPONSE_AUDIO_TIMESTAMP_DONE = "response.audio_timestamp.done" + RESPONSE_CONTENT_PART_ADDED = "response.content_part.added" + RESPONSE_CONTENT_PART_DONE = "response.content_part.done" + RESPONSE_CREATED = "response.created" + RESPONSE_DONE = "response.done" + RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA = "response.function_call_arguments.delta" + RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE = "response.function_call_arguments.done" + RESPONSE_MCP_CALL_ARGUMENTS_DELTA = "response.mcp_call_arguments.delta" + RESPONSE_MCP_CALL_ARGUMENTS_DONE = "response.mcp_call_arguments.done" + RESPONSE_MCP_CALL_COMPLETED = "response.mcp_call.completed" + RESPONSE_MCP_CALL_FAILED = "response.mcp_call.failed" + RESPONSE_MCP_CALL_IN_PROGRESS = "response.mcp_call.in_progress" + RESPONSE_OUTPUT_AUDIO_DELTA = "response.output_audio.delta" + RESPONSE_OUTPUT_AUDIO_DONE = "response.output_audio.done" + RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA = "response.output_audio_transcript.delta" + RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE = "response.output_audio_transcript.done" + RESPONSE_OUTPUT_ITEM_ADDED = "response.output_item.added" + RESPONSE_OUTPUT_ITEM_DONE = "response.output_item.done" + RESPONSE_OUTPUT_TEXT_DELTA = "response.output_text.delta" + RESPONSE_OUTPUT_TEXT_DONE = "response.output_text.done" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA = "response.system_tool_arguments.delta" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE = "response.system_tool_arguments.done" + RESPONSE_VIDEO_DELTA = "response.video.delta" + RTC_CALL_ERROR = "rtc.call.error" + RTC_CALL_SDP_CREATED = "rtc.call.sdp.created" + SESSION_AVATAR_CONNECTING = "session.avatar.connecting" + SESSION_AVATAR_SWITCH_TO_IDLE = "session.avatar.switch_to_idle" + SESSION_AVATAR_SWITCH_TO_SPEAKING = "session.avatar.switch_to_speaking" + SESSION_CREATED = "session.created" + SESSION_HANDOFF_ABORTED = "session.handoff.aborted" + SESSION_HANDOFF_COMPLETED = "session.handoff.completed" + SESSION_HANDOFF_STARTED = "session.handoff.started" + SESSION_SUBAGENT_ABORTED = "session.subagent.aborted" + SESSION_SUBAGENT_COMPLETED = "session.subagent.completed" + SESSION_SUBAGENT_STARTED = "session.subagent.started" + SESSION_UPDATED = "session.updated" + WARNING = "warning" + + + class azure.ai.projects.models.Reasoning(_Model): + context: Optional[Literal["auto", "current_turn", "all_turns"]] + effort: Optional[Union[str, ReasoningEffort]] + generate_summary: Optional[Literal["auto", "concise", "detailed"]] + mode: Optional[Union[str, ReasoningModeEnum]] + summary: Optional[Literal["auto", "concise", "detailed"]] + + @overload + def __init__( + self, + *, + context: Optional[Literal[auto, current_turn, all_turns]] = ..., + effort: Optional[Union[str, ReasoningEffort]] = ..., + generate_summary: Optional[Literal[auto, concise, detailed]] = ..., + mode: Optional[Union[str, ReasoningModeEnum]] = ..., + summary: Optional[Literal[auto, concise, detailed]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + MAX = "max" + MEDIUM = "medium" + MINIMAL = "minimal" + NONE = "none" + XHIGH = "xhigh" + + + class azure.ai.projects.models.ReasoningModeEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + PRO = "pro" + STANDARD = "standard" + + + class azure.ai.projects.models.RecurrenceSchedule(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RecurrenceTrigger(Trigger, discriminator='Recurrence'): + end_time: Optional[datetime] + interval: int + schedule: RecurrenceSchedule + start_time: Optional[datetime] + time_zone: Optional[str] + type: Literal[TriggerType.RECURRENCE] + + @overload + def __init__( + self, + *, + end_time: Optional[datetime] = ..., + interval: int, + schedule: RecurrenceSchedule, + start_time: Optional[datetime] = ..., + time_zone: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RecurrenceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DAILY = "Daily" + HOURLY = "Hourly" + MONTHLY = "Monthly" + WEEKLY = "Weekly" + + + class azure.ai.projects.models.RedTeam(_Model): + application_scenario: Optional[str] + attack_strategies: Optional[list[Union[str, AttackStrategy]]] + display_name: Optional[str] + name: str + num_turns: Optional[int] + properties: Optional[dict[str, str]] + risk_categories: Optional[list[Union[str, RiskCategory]]] + simulation_only: Optional[bool] + status: Optional[str] + tags: Optional[dict[str, str]] + target: RedTeamTargetConfig + + @overload + def __init__( + self, + *, + application_scenario: Optional[str] = ..., + attack_strategies: Optional[list[Union[str, AttackStrategy]]] = ..., + display_name: Optional[str] = ..., + num_turns: Optional[int] = ..., + properties: Optional[dict[str, str]] = ..., + risk_categories: Optional[list[Union[str, RiskCategory]]] = ..., + simulation_only: Optional[bool] = ..., + tags: Optional[dict[str, str]] = ..., + target: RedTeamTargetConfig + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RedTeamEvalRunDataSource(TypedDict, total=False): + key "item_generation_params": Required[Any] + key "target": Required[Union[AzureAIAgentTargetParam, AzureAIModelTargetParam, dict[str, Any]]] + key "type": Required[Literal["azure_ai_red_team"]] + + + class azure.ai.projects.models.RedTeamTargetConfig(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ReinforcementFineTuningDataGenerationJob(DataGenerationJob, discriminator='reinforcement_finetuning_preview'): + created_at: datetime + error: ApiError + finished_at: datetime + generation_configuration: DataGenerationJobConfiguration + id: str + name: str + output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] + result: DataGenerationJobResult + scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] + sources: list[DataGenerationJobSource] + status: Union[str, JobStatus] + + @overload + def __init__( + self, + *, + generation_configuration: DataGenerationJobConfiguration, + name: str, + output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] = ..., + sources: list[DataGenerationJobSource] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobInputs(DataGenerationJobInputs, discriminator='reinforcement_finetuning_preview'): + generation_configuration: DataGenerationJobConfiguration + name: str + output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] + scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] + sources: list[DataGenerationJobSource] + + @overload + def __init__( + self, + *, + generation_configuration: DataGenerationJobConfiguration, + name: str, + output_configuration: Optional[ReinforcementFineTuningDataGenerationJobOutputConfiguration] = ..., + sources: list[DataGenerationJobSource] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobOutputConfiguration(_Model): + merge_file_id: Optional[str] + name: str + write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] + + @overload + def __init__( + self, + *, + merge_file_id: Optional[str] = ..., + name: str, + write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ReminderPreviewToolboxTool(ToolboxTool, discriminator='reminder_preview'): + description: str + name: str + tool_configs: dict[str, ToolConfig] + type: Literal[ToolboxToolType.REMINDER_PREVIEW] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + name: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ResponseRetrievalItemGenerationParams(TypedDict, total=False): + key "data_mapping": Required[Dict[str, str]] + key "max_num_turns": int + key "source": Required[Union[SourceFileContent, SourceFileID]] + key "type": Required[Literal["response_retrieval"]] + + + class azure.ai.projects.models.ResponseUsageInputTokensDetails(_Model): + cache_write_tokens: int + cached_tokens: int + + @overload + def __init__( + self, + *, + cache_write_tokens: int, + cached_tokens: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ResponseUsageOutputTokensDetails(_Model): + reasoning_tokens: int + + @overload + def __init__( + self, + *, + reasoning_tokens: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ResponseUsageResource(_Model): + input_tokens: int + input_tokens_details: InputTokensDetailsResource + output_tokens: int + output_tokens_details: OutputTokensDetailsResource + total_tokens: int + + @overload + def __init__( + self, + *, + input_tokens: int, + input_tokens_details: InputTokensDetailsResource, + output_tokens: int, + output_tokens_details: OutputTokensDetailsResource, + total_tokens: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ResponsesProtocolConfiguration(_Model): + + + class azure.ai.projects.models.RiskCategory(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CODE_VULNERABILITY = "CodeVulnerability" + HATE_UNFAIRNESS = "HateUnfairness" + PROHIBITED_ACTIONS = "ProhibitedActions" + PROTECTED_MATERIAL = "ProtectedMaterial" + SELF_HARM = "SelfHarm" + SENSITIVE_DATA_LEAKAGE = "SensitiveDataLeakage" + SEXUAL = "Sexual" + TASK_ADHERENCE = "TaskAdherence" + UNGROUNDED_ATTRIBUTES = "UngroundedAttributes" + VIOLENCE = "Violence" + + + class azure.ai.projects.models.Routine(_Model): + action: Optional[RoutineAction] + created_at: Optional[datetime] + description: Optional[str] + enabled: bool + name: Optional[str] + triggers: Optional[dict[str, RoutineTrigger]] + updated_at: Optional[datetime] + + @overload + def __init__( + self, + *, + action: Optional[RoutineAction] = ..., + created_at: Optional[datetime] = ..., + description: Optional[str] = ..., + enabled: bool, + name: Optional[str] = ..., + triggers: Optional[dict[str, RoutineTrigger]] = ..., + updated_at: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RoutineAction(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RoutineActionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + INVOKE_AGENT_INVOCATIONS_API = "invoke_agent_invocations_api" + INVOKE_AGENT_RESPONSES_API = "invoke_agent_responses_api" + + + class azure.ai.projects.models.RoutineAttemptSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + EVENT_FIRE = "event_fire" + MANUAL_DISPATCH = "manual_dispatch" + QUEUED_DISPATCH = "queued_dispatch" + SCHEDULE_DELIVERY = "schedule_delivery" + TIMER_DELIVERY = "timer_delivery" + + + class azure.ai.projects.models.RoutineAuthorization(_Model): + identity: Optional[Union[str, RoutineDispatchIdentity]] + + @overload + def __init__( + self, + *, + identity: Optional[Union[str, RoutineDispatchIdentity]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RoutineDispatchIdentity(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AGENT = "agent" + CREATOR = "creator" + + + class azure.ai.projects.models.RoutineDispatchPayload(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RoutineDispatchPayloadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + INVOKE_AGENT_INVOCATIONS_API = "invoke_agent_invocations_api" + INVOKE_AGENT_RESPONSES_API = "invoke_agent_responses_api" + + + class azure.ai.projects.models.RoutineRun(_Model): + action_correlation_id: Optional[str] + action_type: Optional[Union[str, RoutineActionType]] + agent_endpoint_id: Optional[str] + agent_id: Optional[str] + attempt_source: Optional[Union[str, RoutineAttemptSource]] + conversation_id: Optional[str] + dispatch_id: Optional[str] + ended_at: Optional[datetime] + error_message: Optional[str] + error_status_code: Optional[int] + error_type: Optional[str] + id: str + phase: Optional[Union[str, RoutineRunPhase]] + response_id: Optional[str] + scheduled_fire_at: Optional[datetime] + session_id: Optional[str] + started_at: Optional[datetime] + status: Optional[RoutineRunStatus] + task_id: Optional[str] + trigger_event_payload: Optional[dict[str, Any]] + trigger_name: Optional[str] + trigger_type: Optional[Union[str, RoutineTriggerType]] + triggered_at: Optional[datetime] + + @overload + def __init__( + self, + *, + action_correlation_id: Optional[str] = ..., + action_type: Optional[Union[str, RoutineActionType]] = ..., + agent_endpoint_id: Optional[str] = ..., + agent_id: Optional[str] = ..., + attempt_source: Optional[Union[str, RoutineAttemptSource]] = ..., + conversation_id: Optional[str] = ..., + dispatch_id: Optional[str] = ..., + ended_at: Optional[datetime] = ..., + error_message: Optional[str] = ..., + error_status_code: Optional[int] = ..., + error_type: Optional[str] = ..., + phase: Optional[Union[str, RoutineRunPhase]] = ..., + response_id: Optional[str] = ..., + scheduled_fire_at: Optional[datetime] = ..., + session_id: Optional[str] = ..., + started_at: Optional[datetime] = ..., + status: Optional[RoutineRunStatus] = ..., + task_id: Optional[str] = ..., + trigger_event_payload: Optional[dict[str, Any]] = ..., + trigger_name: Optional[str] = ..., + trigger_type: Optional[Union[str, RoutineTriggerType]] = ..., + triggered_at: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RoutineRunPhase(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COMPLETED = "completed" + DISPATCHING = "dispatching" + FAILED = "failed" + QUEUED = "queued" + + + class azure.ai.projects.models.RoutineTrigger(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RoutineTriggerType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CUSTOM = "custom" + GITHUB_ISSUE = "github_issue" + SCHEDULE = "schedule" + TIMER = "timer" + + + class azure.ai.projects.models.RubricBasedEvaluatorDefinition(EvaluatorDefinition, discriminator='rubric'): + data_schema: dict[str, any] + dimensions: list[Dimension] + init_parameters: dict[str, any] + metrics: dict[str, EvaluatorMetric] + pass_threshold: Optional[float] + type: Literal[EvaluatorDefinitionType.RUBRIC] + + @overload + def __init__( + self, + *, + data_schema: Optional[dict[str, Any]] = ..., + dimensions: list[Dimension], + init_parameters: Optional[dict[str, Any]] = ..., + metrics: Optional[dict[str, EvaluatorMetric]] = ..., + pass_threshold: Optional[float] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RubricGenerationInputQualityWarning(_Model): + code: Union[str, RubricGenerationInputQualityWarningCode] + message: str + severity: Union[str, RubricGenerationInputQualityWarningSeverity] + source: Union[str, RubricGenerationInputQualityWarningSource] + source_index: Optional[int] + + @overload + def __init__( + self, + *, + code: Union[str, RubricGenerationInputQualityWarningCode], + message: str, + severity: Union[str, RubricGenerationInputQualityWarningSeverity], + source: Union[str, RubricGenerationInputQualityWarningSource], + source_index: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.RubricGenerationInputQualityWarningCode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + EMPTY_AGENT_INSTRUCTIONS = "empty_agent_instructions" + EMPTY_DATASET_CONTENT = "empty_dataset_content" + EMPTY_PROMPT = "empty_prompt" + INSUFFICIENT_TOTAL_INPUT = "insufficient_total_input" + LOW_TRACE_COUNT = "low_trace_count" + SHORT_AGENT_INSTRUCTIONS = "short_agent_instructions" + SHORT_DATASET_CONTENT = "short_dataset_content" + SHORT_PROMPT = "short_prompt" + + + class azure.ai.projects.models.RubricGenerationInputQualityWarningSeverity(str, Enum, metaclass=CaseInsensitiveEnumMeta): + WARNING = "warning" + + + class azure.ai.projects.models.RubricGenerationInputQualityWarningSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AGENT = "agent" + AGGREGATE = "aggregate" + DATASET = "dataset" + PROMPT = "prompt" + + + class azure.ai.projects.models.SASCredentials(BaseCredentials, discriminator='SAS'): + sas_token: Optional[str] + type: Literal[CredentialType.SAS] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SampleType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + EVALUATION_RESULT_SAMPLE = "EvaluationResultSample" + + + class azure.ai.projects.models.Schedule(_Model): + description: Optional[str] + display_name: Optional[str] + enabled: bool + properties: Optional[dict[str, str]] + provisioning_status: Optional[Union[str, ScheduleProvisioningStatus]] + schedule_id: str + system_data: dict[str, str] + tags: Optional[dict[str, str]] + task: ScheduleTask + trigger: Trigger + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + display_name: Optional[str] = ..., + enabled: bool, + properties: Optional[dict[str, str]] = ..., + tags: Optional[dict[str, str]] = ..., + task: ScheduleTask, + trigger: Trigger + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ScheduleProvisioningStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CREATING = "Creating" + DELETING = "Deleting" + FAILED = "Failed" + SUCCEEDED = "Succeeded" + UPDATING = "Updating" + + + class azure.ai.projects.models.ScheduleRoutineTrigger(RoutineTrigger, discriminator='schedule'): + cron_expression: str + time_zone: str + type: Literal[RoutineTriggerType.SCHEDULE] + + @overload + def __init__( + self, + *, + cron_expression: str, + time_zone: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ScheduleRun(_Model): + error: Optional[str] + properties: dict[str, str] + run_id: str + schedule_id: str + success: bool + trigger_time: Optional[datetime] + + @overload + def __init__( + self, + *, + schedule_id: str, + trigger_time: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ScheduleTask(_Model): + configuration: Optional[dict[str, str]] + type: str + + @overload + def __init__( + self, + *, + configuration: Optional[dict[str, str]] = ..., + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ScheduleTaskType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + EVALUATION = "Evaluation" + INSIGHT = "Insight" + + + class azure.ai.projects.models.ScoreProbabilityResource(_Model): + label: str + probability: float + value: int + + @overload + def __init__( + self, + *, + label: str, + probability: float, + value: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SearchContentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + IMAGE = "image" + TEXT = "text" + + + class azure.ai.projects.models.SearchContextSize(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + MEDIUM = "medium" + + + class azure.ai.projects.models.SessionConfiguration(_Model): + idle_timeout_seconds: Optional[timedelta] + + @overload + def __init__( + self, + *, + idle_timeout_seconds: Optional[timedelta] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SessionDirectoryEntry(_Model): + is_directory: bool + modified_time: datetime + name: str + size: int + + @overload + def __init__( + self, + *, + is_directory: bool, + modified_time: datetime, + name: str, + size: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SessionFileWriteResult(_Model): + bytes_written: int + path: str + + @overload + def __init__( + self, + *, + bytes_written: int, + path: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SessionLogEvent(_Model): + data: str + event: Union[str, SessionLogEventType] + + @overload + def __init__( + self, + *, + data: str, + event: Union[str, SessionLogEventType] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SessionLogEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LOG = "log" + + + class azure.ai.projects.models.SharepointGroundingToolParameters(_Model): + project_connections: Optional[list[ToolProjectConnection]] + + @overload + def __init__( + self, + *, + project_connections: Optional[list[ToolProjectConnection]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SharepointPreviewTool(Tool, discriminator='sharepoint_grounding_preview'): + sharepoint_grounding_preview: SharepointGroundingToolParameters + type: Literal[ToolType.SHAREPOINT_GROUNDING_PREVIEW] + + @overload + def __init__( + self, + *, + sharepoint_grounding_preview: SharepointGroundingToolParameters + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ShellToolboxTool(ToolboxTool, discriminator='shell'): + allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] + description: str + environment: ToolboxShellEnvironment + name: str + tool_configs: dict[str, ToolConfig] + type: Literal[ToolboxToolType.SHELL] + + @overload + def __init__( + self, + *, + allowed_callers: Optional[list[Union[str, CallableToolAllowedCaller]]] = ..., + description: Optional[str] = ..., + environment: ToolboxShellEnvironment, + name: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SimpleQnADataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='simple_qna'): + max_samples: int + model_options: DataGenerationModelOptions + question_types: Optional[list[Union[str, SimpleQnAFineTuningQuestionType]]] + train_split: float + type: Literal[DataGenerationJobType.SIMPLE_QNA] + + @overload + def __init__( + self, + *, + max_samples: int, + model_options: Optional[DataGenerationModelOptions] = ..., + question_types: Optional[list[Union[str, SimpleQnAFineTuningQuestionType]]] = ..., + train_split: Optional[float] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SimpleQnAFineTuningQuestionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LONG_ANSWER = "long_answer" + SHORT_ANSWER = "short_answer" + + + class azure.ai.projects.models.SimulationSeedDataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='simulation_seed'): + max_samples: int + model_options: DataGenerationModelOptions + train_split: float + type: Literal[DataGenerationJobType.SIMULATION_SEED] + + @overload + def __init__( + self, + *, + max_samples: int, + model_options: Optional[DataGenerationModelOptions] = ..., + train_split: Optional[float] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SipAddress(TelephonyAddress, discriminator='sip'): + type: Literal[TelephonyAddressType.SIP] + value: str + + @overload + def __init__( + self, + *, + value: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SipTelephonyBinding(TelephonyBinding, discriminator='sip'): + allowed_calling_numbers: Optional[list[str]] + connection_name: str + id: str + incoming_call_url: str + label: str + phone_number: Optional[str] + provider: Literal[TelephonyProvider.SIP] + + @overload + def __init__( + self, + *, + allowed_calling_numbers: Optional[list[str]] = ..., + connection_name: str, + label: Optional[str] = ..., + phone_number: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SipTelephonyBindingListItem(TelephonyBindingListItem, discriminator='sip'): + allowed_calling_numbers: Optional[list[str]] + connection_name: str + etag: str + id: str + incoming_call_url: str + label: str + phone_number: Optional[str] + provider: Literal[TelephonyProvider.SIP] + + @overload + def __init__( + self, + *, + allowed_calling_numbers: Optional[list[str]] = ..., + connection_name: str, + id: str, + incoming_call_url: str, + label: Optional[str] = ..., + phone_number: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SkillDetails(_Model): + created_at: datetime + default_version: str + description: str + id: str + latest_version: str + name: str + + @overload + def __init__( + self, + *, + created_at: datetime, + default_version: str, + description: str, + id: str, + latest_version: str, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SkillInlineContent(_Model): + allowed_tools: Optional[list[str]] + compatibility: Optional[str] + description: str + instructions: str + license: Optional[str] + metadata: Optional[dict[str, str]] + + @overload + def __init__( + self, + *, + allowed_tools: Optional[list[str]] = ..., + compatibility: Optional[str] = ..., + description: str, + instructions: str, + license: Optional[str] = ..., + metadata: Optional[dict[str, str]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SkillReference(_Model): + name: str + version: Optional[str] + + @overload + def __init__( + self, + *, + name: str, + version: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SkillReferenceParam(ContainerSkill, discriminator='skill_reference'): + skill_id: str + type: Literal[ContainerSkillType.SKILL_REFERENCE] + version: Optional[str] + + @overload + def __init__( + self, + *, + skill_id: str, + version: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SkillVersion(_Model): + created_at: datetime + description: str + id: str + name: str + skill_id: str + version: str + + @overload + def __init__( + self, + *, + created_at: datetime, + description: str, + id: str, + name: str, + skill_id: str, + version: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SpecificApplyPatchParam(ToolChoiceParam, discriminator='apply_patch'): + type: Literal[ToolChoiceParamType.APPLY_PATCH] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SpecificFunctionShellParam(ToolChoiceParam, discriminator='shell'): + type: Literal[ToolChoiceParamType.SHELL] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SpecificProgrammaticToolCallingParam(ToolChoiceParam, discriminator='programmatic_tool_calling'): + type: Literal[ToolChoiceParamType.PROGRAMMATIC_TOOL_CALLING] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SteeringPromptOptimizationContext(OptimizationContext, discriminator='steering_prompt'): + prompt: str + type: Literal[OptimizationContextType.STEERING_PROMPT] + + @overload + def __init__( + self, + *, + prompt: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.StructuredInputDefinition(_Model): + default_value: Optional[Any] + description: Optional[str] + required: Optional[bool] + schema: Optional[dict[str, Any]] + + @overload + def __init__( + self, + *, + default_value: Optional[Any] = ..., + description: Optional[str] = ..., + required: Optional[bool] = ..., + schema: Optional[dict[str, Any]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.StructuredOutputDefinition(_Model): + description: str + name: str + schema: dict[str, Any] + strict: bool + + @overload + def __init__( + self, + *, + description: str, + name: str, + schema: dict[str, Any], + strict: bool + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SupervisedFineTuningDataGenerationJob(DataGenerationJob, discriminator='supervised_finetuning_preview'): + created_at: datetime + error: ApiError + finished_at: datetime + generation_configuration: DataGenerationJobConfiguration + id: str + name: str + output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] + result: DataGenerationJobResult + scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] + sources: list[DataGenerationJobSource] + status: Union[str, JobStatus] + + @overload + def __init__( + self, + *, + generation_configuration: DataGenerationJobConfiguration, + name: str, + output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] = ..., + sources: list[DataGenerationJobSource] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SupervisedFineTuningDataGenerationJobInputs(DataGenerationJobInputs, discriminator='supervised_finetuning_preview'): + generation_configuration: DataGenerationJobConfiguration + name: str + output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] + scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] + sources: list[DataGenerationJobSource] + + @overload + def __init__( + self, + *, + generation_configuration: DataGenerationJobConfiguration, + name: str, + output_configuration: Optional[SupervisedFineTuningDataGenerationJobOutputConfiguration] = ..., + sources: list[DataGenerationJobSource] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration(_Model): + merge_file_id: Optional[str] + name: str + write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] + + @overload + def __init__( + self, + *, + merge_file_id: Optional[str] = ..., + name: str, + write_mode: Optional[Union[str, DataGenerationJobOutputWriteMode]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TargetAttribute(str, Enum, metaclass=CaseInsensitiveEnumMeta): + INSTRUCTIONS = "instructions" + MODEL = "model" + SKILLS = "skills" + TOOLS = "tools" + + + class azure.ai.projects.models.TargetCompletionEvalRunDataSource(TypedDict, total=False): + key "input_messages": Required[InputMessagesItemReference] + key "source": Required[Union[SourceFileContent, SourceFileID]] + key "target": Required[Union[AzureAIAgentTargetParam, AzureAIModelTargetParam, dict[str, Any]]] + key "type": Required[Literal["azure_ai_target_completions"]] + + + class azure.ai.projects.models.TaxonomyCategory(_Model): + description: Optional[str] + id: str + name: str + properties: Optional[dict[str, str]] + risk_category: Union[str, RiskCategory] + sub_categories: list[TaxonomySubCategory] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + id: str, + name: str, + properties: Optional[dict[str, str]] = ..., + risk_category: Union[str, RiskCategory], + sub_categories: list[TaxonomySubCategory] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TaxonomySubCategory(_Model): + description: Optional[str] + enabled: bool + id: str + name: str + properties: Optional[dict[str, str]] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + enabled: bool, + id: str, + name: str, + properties: Optional[dict[str, str]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TeamsAddress(TelephonyAddress, discriminator='teams'): + type: Literal[TelephonyAddressType.TEAMS] + value: str + + @overload + def __init__( + self, + *, + value: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TeamsPhoneExtensibilityTelephonyBinding(TelephonyBinding, discriminator='teams_phone_extensibility'): + connection_name: str + id: str + incoming_call_url: str + label: str + phone_number: Optional[str] + provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] + resource_account_object_id: str + + @overload + def __init__( + self, + *, + connection_name: str, + label: Optional[str] = ..., + phone_number: Optional[str] = ..., + resource_account_object_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TeamsPhoneExtensibilityTelephonyBindingListItem(TelephonyBindingListItem, discriminator='teams_phone_extensibility'): + connection_name: str + etag: str + id: str + incoming_call_url: str + label: str + phone_number: Optional[str] + provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] + resource_account_object_id: str + + @overload + def __init__( + self, + *, + connection_name: str, + id: str, + incoming_call_url: str, + label: Optional[str] = ..., + phone_number: Optional[str] = ..., + resource_account_object_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelemetryConfig(_Model): + endpoints: list[TelemetryEndpoint] + + @overload + def __init__( + self, + *, + endpoints: list[TelemetryEndpoint] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelemetryDataKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CONTAINER_OTEL = "ContainerOtel" + CONTAINER_STDOUT_STDERR = "ContainerStdoutStderr" + METRICS = "Metrics" + + + class azure.ai.projects.models.TelemetryEndpoint(_Model): + auth: Optional[TelemetryEndpointAuth] + data: list[Union[str, TelemetryDataKind]] + kind: str + + @overload + def __init__( + self, + *, + auth: Optional[TelemetryEndpointAuth] = ..., + data: list[Union[str, TelemetryDataKind]], + kind: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelemetryEndpointAuth(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelemetryEndpointAuthType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HEADER = "header" + + + class azure.ai.projects.models.TelemetryEndpointKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + OTLP = "OTLP" + + + class azure.ai.projects.models.TelemetryTransportProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): + GRPC = "Grpc" + HTTP = "Http" + + + class azure.ai.projects.models.TelephonyAddress(_Model): + type: str + value: str + + @overload + def __init__( + self, + *, + type: str, + value: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyAddressType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + PHONE_NUMBER = "phone_number" + SIP = "sip" + TEAMS = "teams" + + + class azure.ai.projects.models.TelephonyBinding(_Model): + connection_name: str + id: str + incoming_call_url: str + label: Optional[str] + provider: str + + @overload + def __init__( + self, + *, + connection_name: str, + label: Optional[str] = ..., + provider: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyBindingListItem(_Model): + connection_name: str + etag: str + id: str + incoming_call_url: str + label: Optional[str] + provider: str + + @overload + def __init__( + self, + *, + connection_name: str, + id: str, + incoming_call_url: str, + label: Optional[str] = ..., + provider: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallDurationBasis(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ANSWERED = "answered" + RECEIVED = "received" + + + class azure.ai.projects.models.TelephonyCallEndReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ADMISSION_CHECK_FAILED = "admission_check_failed" + ADMISSION_REJECTED = "admission_rejected" + AGENT_SESSION_CONNECT_FAILED = "agent_session_connect_failed" + ANSWER_FAILED = "answer_failed" + BINDING_NOT_FOUND = "binding_not_found" + BINDING_SUSPENDED = "binding_suspended" + BRIDGE_CANCELLED = "bridge_cancelled" + BRIDGE_FAILED = "bridge_failed" + CREDENTIAL_RESOLUTION_FAILED = "credential_resolution_failed" + ENDPOINT_RESOLUTION_FAILED = "endpoint_resolution_failed" + INGRESS_SETUP_FAILED = "ingress_setup_failed" + INVALID_BINDING_CONFIGURATION = "invalid_binding_configuration" + INVALID_WEBHOOK_PAYLOAD = "invalid_webhook_payload" + LIVE_CALL_CONFLICT = "live_call_conflict" + LIVE_CALL_PERSISTENCE_FAILED = "live_call_persistence_failed" + MANAGED_HANGUP = "managed_hangup" + MANAGED_TRANSFER = "managed_transfer" + MANAGE_HANGUP_FAILED = "manage_hangup_failed" + MANAGE_TRANSFER_FAILED = "manage_transfer_failed" + MEDIA_STREAM_ENDED = "media_stream_ended" + PROVIDER_BUSY = "provider_busy" + PROVIDER_CANCELLED = "provider_cancelled" + PROVIDER_DISCONNECTED = "provider_disconnected" + PROVIDER_FAILED = "provider_failed" + PROVIDER_NO_ANSWER = "provider_no_answer" + PROVIDER_RESOURCE_MISMATCH = "provider_resource_mismatch" + PROVIDER_STREAM_ERROR = "provider_stream_error" + PROVIDER_STREAM_STOPPED = "provider_stream_stopped" + ROUTE_AGENT_MISMATCH = "route_agent_mismatch" + WEBHOOK_VALIDATION_FAILED = "webhook_validation_failed" + + + class azure.ai.projects.models.TelephonyCallJob(_Model): + agent_name: str + attempt_count: int + campaign_name: Optional[str] + cancellation: Optional[TelephonyCallJobCancellation] + connection_name: str + created_at: datetime + destination: TelephonyAddress + id: str + next_attempt_at: Optional[datetime] + purpose: Optional[str] + retry_policy: TelephonyOutboundRetryPolicy + revision: int + schedule: Optional[TelephonyCallJobSchedule] + source: TelephonyAddress + status: Union[str, TelephonyCallJobStatus] + structured_inputs: Optional[dict[str, Any]] + terminal_reason: Optional[Union[str, TelephonyCallJobTerminalReason]] + updated_at: datetime + + @overload + def __init__( + self, + *, + connection_name: str, + destination: TelephonyAddress, + purpose: Optional[str] = ..., + retry_policy: TelephonyOutboundRetryPolicy, + schedule: Optional[TelephonyCallJobSchedule] = ..., + source: TelephonyAddress, + structured_inputs: Optional[dict[str, Any]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallJobCancellation(_Model): + mode: str + requested_at: datetime + requested_by: str + revision: int + + @overload + def __init__( + self, + *, + mode: str, + requested_at: datetime, + requested_by: str, + revision: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallJobCreate(_Model): + connection_name: str + destination: TelephonyAddress + purpose: Optional[str] + retry_policy: Optional[TelephonyOutboundRetryPolicy] + schedule: Optional[TelephonyCallJobSchedule] + source: TelephonyAddress + structured_inputs: Optional[dict[str, Any]] + + @overload + def __init__( + self, + *, + connection_name: str, + destination: TelephonyAddress, + purpose: Optional[str] = ..., + retry_policy: Optional[TelephonyOutboundRetryPolicy] = ..., + schedule: Optional[TelephonyCallJobSchedule] = ..., + source: TelephonyAddress, + structured_inputs: Optional[dict[str, Any]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallJobSchedule(_Model): + expires_at: Optional[datetime] + not_before: Optional[datetime] + + @overload + def __init__( + self, + *, + expires_at: Optional[datetime] = ..., + not_before: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallJobStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ACCEPTED = "accepted" + BLOCKED = "blocked" + CANCELLATION_REQUESTED = "cancellation_requested" + CANCELLED = "cancelled" + COMPLETED = "completed" + DISPATCHING = "dispatching" + EXPIRED = "expired" + FAILED = "failed" + IN_PROGRESS = "in_progress" + QUEUED = "queued" + WAITING_FOR_RETRY = "waiting_for_retry" + WAITING_FOR_SCHEDULE = "waiting_for_schedule" + + + class azure.ai.projects.models.TelephonyCallJobTerminalReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ANSWER_FAILED = "answer_failed" + BRIDGE_CANCELLED = "bridge_cancelled" + BRIDGE_FAILED = "bridge_failed" + CAMPAIGN_CANCELLED = "campaign_cancelled" CAMPAIGN_COMPLETED = "campaign_completed" CAMPAIGN_FAILED = "campaign_failed" CAMPAIGN_NOT_FOUND = "campaign_not_found" @@ -13718,680 +17020,1528 @@ namespace azure.ai.projects.models VOICE_SESSION_CONFIGURATION_INVALID = "voice_session_configuration_invalid" - class azure.ai.projects.models.TelephonyCallLifecycleEvent(_Model): - name: Union[str, TelephonyCallLifecycleEventName] - observed_at: datetime - occurred_at: Optional[datetime] - outcome: Union[str, TelephonyCallLifecycleEventOutcome] - provider_event_id: Optional[str] - provider_sequence: Optional[int] - provider_status_code: Optional[int] - provider_sub_code: Optional[int] - reason: Optional[Union[str, TelephonyCallLifecycleEventReason]] - sequence: int - source: Union[str, TelephonyCallLifecycleEventSource] - timestamp_source: Union[str, TelephonyCallTimestampSource] + class azure.ai.projects.models.TelephonyCallLifecycleEvent(_Model): + name: Union[str, TelephonyCallLifecycleEventName] + observed_at: datetime + occurred_at: Optional[datetime] + outcome: Union[str, TelephonyCallLifecycleEventOutcome] + provider_event_id: Optional[str] + provider_sequence: Optional[int] + provider_status_code: Optional[int] + provider_sub_code: Optional[int] + reason: Optional[Union[str, TelephonyCallLifecycleEventReason]] + sequence: int + source: Union[str, TelephonyCallLifecycleEventSource] + timestamp_source: Union[str, TelephonyCallTimestampSource] + + @overload + def __init__( + self, + *, + name: Union[str, TelephonyCallLifecycleEventName], + observed_at: datetime, + occurred_at: Optional[datetime] = ..., + outcome: Union[str, TelephonyCallLifecycleEventOutcome], + provider_event_id: Optional[str] = ..., + provider_sequence: Optional[int] = ..., + provider_status_code: Optional[int] = ..., + provider_sub_code: Optional[int] = ..., + reason: Optional[Union[str, TelephonyCallLifecycleEventReason]] = ..., + source: Union[str, TelephonyCallLifecycleEventSource], + timestamp_source: Union[str, TelephonyCallTimestampSource] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallLifecycleEventName(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AGENT_SESSION_CONNECT = "telephony.agent_session.connect" + BINDING_RESOLVE = "telephony.binding.resolve" + CALL_DISCONNECT = "telephony.call.disconnect" + CALL_HANGUP = "telephony.call.hangup" + CALL_TRANSFER = "telephony.call.transfer" + FIRST_AGENT_AUDIO = "telephony.media.first_agent_audio" + FIRST_CALLER_AUDIO = "telephony.media.first_caller_audio" + MEDIA_CONNECT = "telephony.media.connect" + PROVIDER_ANSWER = "telephony.provider.answer" + WEBHOOK_RECEIVED = "telephony.webhook.received" + WEBHOOK_VALIDATION = "telephony.webhook.validation" + + + class azure.ai.projects.models.TelephonyCallLifecycleEventOutcome(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CANCELLED = "cancelled" + FAILED = "failed" + OBSERVED = "observed" + REJECTED = "rejected" + STARTED = "started" + SUCCEEDED = "succeeded" + + + class azure.ai.projects.models.TelephonyCallLifecycleEventReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ADMISSION_CHECK_FAILED = "admission_check_failed" + ADMISSION_REJECTED = "admission_rejected" + AGENT_SESSION_CONNECT_FAILED = "agent_session_connect_failed" + ANSWER_FAILED = "answer_failed" + BINDING_NOT_FOUND = "binding_not_found" + BINDING_SUSPENDED = "binding_suspended" + BRIDGE_CANCELLED = "bridge_cancelled" + BRIDGE_FAILED = "bridge_failed" + CREDENTIAL_RESOLUTION_FAILED = "credential_resolution_failed" + ENDPOINT_RESOLUTION_FAILED = "endpoint_resolution_failed" + INGRESS_SETUP_FAILED = "ingress_setup_failed" + INVALID_BINDING_CONFIGURATION = "invalid_binding_configuration" + INVALID_WEBHOOK_PAYLOAD = "invalid_webhook_payload" + LIVE_CALL_CONFLICT = "live_call_conflict" + LIVE_CALL_PERSISTENCE_FAILED = "live_call_persistence_failed" + MANAGED_HANGUP = "managed_hangup" + MANAGED_TRANSFER = "managed_transfer" + MANAGE_HANGUP_FAILED = "manage_hangup_failed" + MANAGE_TRANSFER_FAILED = "manage_transfer_failed" + MEDIA_STREAM_ENDED = "media_stream_ended" + PROVIDER_BUSY = "provider_busy" + PROVIDER_CANCELLED = "provider_cancelled" + PROVIDER_DISCONNECTED = "provider_disconnected" + PROVIDER_FAILED = "provider_failed" + PROVIDER_NO_ANSWER = "provider_no_answer" + PROVIDER_RESOURCE_MISMATCH = "provider_resource_mismatch" + PROVIDER_STREAM_ERROR = "provider_stream_error" + PROVIDER_STREAM_STOPPED = "provider_stream_stopped" + ROUTE_AGENT_MISMATCH = "route_agent_mismatch" + WEBHOOK_VALIDATION_FAILED = "webhook_validation_failed" + + + class azure.ai.projects.models.TelephonyCallLifecycleEventSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + GATEWAY = "gateway" + TEAMS_PHONE_EXTENSIBILITY = "teams_phone_extensibility" + TWILIO = "twilio" + VOICE_AGENT = "voice_agent" + + + class azure.ai.projects.models.TelephonyCallPhase(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ADMITTED = "admitted" + AGENT_SESSION_READY = "agent_session_ready" + ANSWERED = "answered" + ANSWERING = "answering" + BRIDGING = "bridging" + COMPLETED = "completed" + FAILED = "failed" + MANAGING = "managing" + MEDIA_CONNECTED = "media_connected" + RECEIVED = "received" + REJECTED = "rejected" + VALIDATED = "validated" + + + class azure.ai.projects.models.TelephonyCallRecord(_Model): + agent_session_ready_at: Optional[datetime] + answered_at: Optional[datetime] + caller_number: Optional[str] + duration_ms: Optional[timedelta] + end_reason: Optional[Union[str, TelephonyCallEndReason]] + ended_at: Optional[datetime] + events: list[TelephonyCallLifecycleEvent] + events_truncated: bool + id: str + media_connected_at: Optional[datetime] + phase: Union[str, TelephonyCallPhase] + provider: Union[str, TelephonyProvider] + provider_call_id: Optional[str] + provider_message: Optional[str] + provider_number: Optional[str] + provider_status_code: Optional[int] + provider_sub_code: Optional[int] + started_at: datetime + status: Union[str, TelephonyCallStatus] + timing: TelephonyCallTiming + trace: Optional[TelephonyCallTrace] + + @overload + def __init__( + self, + *, + agent_session_ready_at: Optional[datetime] = ..., + answered_at: Optional[datetime] = ..., + caller_number: Optional[str] = ..., + duration_ms: Optional[timedelta] = ..., + end_reason: Optional[Union[str, TelephonyCallEndReason]] = ..., + ended_at: Optional[datetime] = ..., + events: list[TelephonyCallLifecycleEvent], + events_truncated: bool, + id: str, + media_connected_at: Optional[datetime] = ..., + phase: Union[str, TelephonyCallPhase], + provider: Union[str, TelephonyProvider], + provider_call_id: Optional[str] = ..., + provider_message: Optional[str] = ..., + provider_number: Optional[str] = ..., + provider_status_code: Optional[int] = ..., + provider_sub_code: Optional[int] = ..., + started_at: datetime, + status: Union[str, TelephonyCallStatus], + timing: TelephonyCallTiming, + trace: Optional[TelephonyCallTrace] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FAILED = "failed" + IN_PROGRESS = "in_progress" + SUCCESS = "success" + + + class azure.ai.projects.models.TelephonyCallSummary(_Model): + agent_session_ready_at: Optional[datetime] + answered_at: Optional[datetime] + caller_number: Optional[str] + duration_ms: Optional[timedelta] + end_reason: Optional[Union[str, TelephonyCallEndReason]] + ended_at: Optional[datetime] + id: str + media_connected_at: Optional[datetime] + phase: Union[str, TelephonyCallPhase] + provider: Union[str, TelephonyProvider] + provider_call_id: Optional[str] + provider_message: Optional[str] + provider_number: Optional[str] + provider_status_code: Optional[int] + provider_sub_code: Optional[int] + started_at: datetime + status: Union[str, TelephonyCallStatus] + + @overload + def __init__( + self, + *, + agent_session_ready_at: Optional[datetime] = ..., + answered_at: Optional[datetime] = ..., + caller_number: Optional[str] = ..., + duration_ms: Optional[timedelta] = ..., + end_reason: Optional[Union[str, TelephonyCallEndReason]] = ..., + ended_at: Optional[datetime] = ..., + id: str, + media_connected_at: Optional[datetime] = ..., + phase: Union[str, TelephonyCallPhase], + provider: Union[str, TelephonyProvider], + provider_call_id: Optional[str] = ..., + provider_message: Optional[str] = ..., + provider_number: Optional[str] = ..., + provider_status_code: Optional[int] = ..., + provider_sub_code: Optional[int] = ..., + started_at: datetime, + status: Union[str, TelephonyCallStatus] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallTimestampSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DERIVED = "derived" + GATEWAY = "gateway" + PROVIDER = "provider" + + + class azure.ai.projects.models.TelephonyCallTiming(_Model): + admitted_at: Optional[datetime] + agent_session_ready_at: Optional[datetime] + answer_requested_at: Optional[datetime] + answered_at: Optional[datetime] + duration_basis: Optional[Union[str, TelephonyCallDurationBasis]] + ended_at: Optional[datetime] + first_agent_audio_at: Optional[datetime] + first_caller_audio_at: Optional[datetime] + media_connected_at: Optional[datetime] + received_at: Optional[datetime] + timestamp_source: Union[str, TelephonyCallTimestampSource] + validated_at: Optional[datetime] + + @overload + def __init__( + self, + *, + admitted_at: Optional[datetime] = ..., + agent_session_ready_at: Optional[datetime] = ..., + answer_requested_at: Optional[datetime] = ..., + answered_at: Optional[datetime] = ..., + duration_basis: Optional[Union[str, TelephonyCallDurationBasis]] = ..., + ended_at: Optional[datetime] = ..., + first_agent_audio_at: Optional[datetime] = ..., + first_caller_audio_at: Optional[datetime] = ..., + media_connected_at: Optional[datetime] = ..., + received_at: Optional[datetime] = ..., + timestamp_source: Union[str, TelephonyCallTimestampSource], + validated_at: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallTrace(_Model): + conversation_id: Optional[str] + mode: Optional[Union[str, TelephonyCallTraceMode]] + root_span_id: Optional[str] + status: Union[str, TelephonyCallTraceStatus] + trace_id: Optional[str] + + @overload + def __init__( + self, + *, + conversation_id: Optional[str] = ..., + mode: Optional[Union[str, TelephonyCallTraceMode]] = ..., + root_span_id: Optional[str] = ..., + status: Union[str, TelephonyCallTraceStatus], + trace_id: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCallTraceMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LIVE = "live" + POST_CALL = "post_call" + + + class azure.ai.projects.models.TelephonyCallTraceStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AVAILABLE = "available" + EMITTING = "emitting" + FAILED = "failed" + NOT_APPLICABLE = "not_applicable" + NOT_RECORDED = "not_recorded" + PENDING = "pending" + + + class azure.ai.projects.models.TelephonyCampaign(_Model): + connection_name: str + created_at: datetime + error: Optional[ApiError] + etag: str + finished_at: Optional[datetime] + locked_agent_version: Optional[str] + name: str + operation_id: str + progress: TelephonyCampaignProgress + recipient_dataset: Optional[TelephonyCampaignDatasetReference] + recipients: Optional[list[TelephonyRecipient]] + retry_policy: Optional[TelephonyOutboundRetryPolicy] + schedule: Optional[TelephonyCampaignSchedule] + source: TelephonyAddress + status: Union[str, TelephonyCampaignStatus] + updated_at: datetime + + @overload + def __init__( + self, + *, + connection_name: str, + recipient_dataset: Optional[TelephonyCampaignDatasetReference] = ..., + recipients: Optional[list[TelephonyRecipient]] = ..., + retry_policy: Optional[TelephonyOutboundRetryPolicy] = ..., + schedule: Optional[TelephonyCampaignSchedule] = ..., + source: TelephonyAddress + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCampaignDatasetReference(_Model): + name: str + version: Optional[str] + + @overload + def __init__( + self, + *, + name: str, + version: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCampaignOperation(_Model): + created_at: datetime + error: Optional[ApiError] + finished_at: Optional[datetime] + id: str + kind: Union[str, TelephonyCampaignOperationKind] + status: Union[str, JobStatus] + + + class azure.ai.projects.models.TelephonyCampaignOperationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CANCEL = "cancel" + DELETE = "delete" + VALIDATION = "validation" + + + class azure.ai.projects.models.TelephonyCampaignProgress(_Model): + active: int + cancelled: int + completed: int + expired: int + failed: int + pending: int + total_recipients: Optional[int] + + @overload + def __init__( + self, + *, + active: int, + cancelled: int, + completed: int, + expired: int, + failed: int, + pending: int, + total_recipients: Optional[int] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCampaignSchedule(_Model): + expires_at: Optional[datetime] + type: str + + @overload + def __init__( + self, + *, + expires_at: Optional[datetime] = ..., + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyCampaignScheduleType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + IMMEDIATE = "immediate" + RECIPIENT = "recipient" + SCHEDULED = "scheduled" + + + class azure.ai.projects.models.TelephonyCampaignStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CANCELLED = "cancelled" + CANCELLING = "cancelling" + COMPLETED = "completed" + DELETING = "deleting" + FAILED = "failed" + RUNNING = "running" + VALIDATING = "validating" + + + class azure.ai.projects.models.TelephonyCampaignValidationError(_Model): + error: ApiError + row_number: int + + @overload + def __init__( + self, + *, + error: ApiError, + row_number: int + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyOutboundRetryPolicy(_Model): + max_attempts: Optional[int] + type: str + + @overload + def __init__( + self, + *, + max_attempts: Optional[int] = ..., + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyOutboundRetryPolicyType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FIXED_INTERVAL = "fixed_interval" + + + class azure.ai.projects.models.TelephonyProvider(str, Enum, metaclass=CaseInsensitiveEnumMeta): + SIP = "sip" + TEAMS_PHONE_EXTENSIBILITY = "teams_phone_extensibility" + TWILIO = "twilio" + + + class azure.ai.projects.models.TelephonyRecipient(_Model): + destination: TelephonyAddress + scheduled_at: Optional[datetime] + structured_inputs: Optional[dict[str, Any]] + + @overload + def __init__( + self, + *, + destination: TelephonyAddress, + scheduled_at: Optional[datetime] = ..., + structured_inputs: Optional[dict[str, Any]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyTransferTarget(_Model): + description: str + destination: TelephonyAddress + name: str + + @overload + def __init__( + self, + *, + description: str, + destination: TelephonyAddress, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TelephonyTransferTargets(_Model): + transfer_targets: list[TelephonyTransferTarget] + + @overload + def __init__( + self, + *, + transfer_targets: list[TelephonyTransferTarget] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TestingCriterionAzureAIEvaluator(TypedDict, total=False): + key "data_mapping": Dict[str, str] + key "evaluator_name": Required[str] + key "evaluator_version": str + key "initialization_parameters": Dict[str, Any] + key "name": Required[str] + key "type": Required[Literal["azure_ai_evaluator"]] + + + class azure.ai.projects.models.TextResponseFormat(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TextResponseFormatConfigurationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + JSON_OBJECT = "json_object" + JSON_SCHEMA = "json_schema" + TEXT = "text" + + + class azure.ai.projects.models.TextResponseFormatJsonObject(TextResponseFormat, discriminator='json_object'): + type: Literal[TextResponseFormatConfigurationType.JSON_OBJECT] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TextResponseFormatJsonSchema(TextResponseFormat, discriminator='json_schema'): + description: Optional[str] + name: str + schema: dict[str, Any] + strict: Optional[bool] + type: Literal[TextResponseFormatConfigurationType.JSON_SCHEMA] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + name: str, + schema: dict[str, Any], + strict: Optional[bool] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TextResponseFormatText(TextResponseFormat, discriminator='text'): + type: Literal[TextResponseFormatConfigurationType.TEXT] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.TimerRoutineTrigger(RoutineTrigger, discriminator='timer'): + at: Optional[datetime] + type: Literal[RoutineTriggerType.TIMER] + + @overload + def __init__( + self, + *, + at: Optional[datetime] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.Tool(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceAllowed(ToolChoiceParam, discriminator='allowed_tools'): + mode: Literal["auto", "required"] + tools: list[dict[str, Any]] + type: Literal[ToolChoiceParamType.ALLOWED_TOOLS] + + @overload + def __init__( + self, + *, + mode: Literal["auto", "required"], + tools: list[dict[str, Any]] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceCodeInterpreter(ToolChoiceParam, discriminator='code_interpreter'): + type: Literal[ToolChoiceParamType.CODE_INTERPRETER] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceComputer(ToolChoiceParam, discriminator='computer'): + type: Literal[ToolChoiceParamType.COMPUTER] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceComputerUse(ToolChoiceParam, discriminator='computer_use'): + type: Literal[ToolChoiceParamType.COMPUTER_USE] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceComputerUsePreview(ToolChoiceParam, discriminator='computer_use_preview'): + type: Literal[ToolChoiceParamType.COMPUTER_USE_PREVIEW] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceCustom(ToolChoiceParam, discriminator='custom'): + name: str + type: Literal[ToolChoiceParamType.CUSTOM] + + @overload + def __init__( + self, + *, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceFileSearch(ToolChoiceParam, discriminator='file_search'): + type: Literal[ToolChoiceParamType.FILE_SEARCH] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceFunction(ToolChoiceParam, discriminator='function'): + name: str + type: Literal[ToolChoiceParamType.FUNCTION] + + @overload + def __init__( + self, + *, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceImageGeneration(ToolChoiceParam, discriminator='image_generation'): + type: Literal[ToolChoiceParamType.IMAGE_GENERATION] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceMCP(ToolChoiceParam, discriminator='mcp'): + name: Optional[str] + server_label: str + type: Literal[ToolChoiceParamType.MCP] + + @overload + def __init__( + self, + *, + name: Optional[str] = ..., + server_label: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceOptions(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + NONE = "none" + REQUIRED = "required" + + + class azure.ai.projects.models.ToolChoiceParam(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ALLOWED_TOOLS = "allowed_tools" + APPLY_PATCH = "apply_patch" + CODE_INTERPRETER = "code_interpreter" + COMPUTER = "computer" + COMPUTER_USE = "computer_use" + COMPUTER_USE_PREVIEW = "computer_use_preview" + CUSTOM = "custom" + FILE_SEARCH = "file_search" + FUNCTION = "function" + IMAGE_GENERATION = "image_generation" + MCP = "mcp" + PROGRAMMATIC_TOOL_CALLING = "programmatic_tool_calling" + SHELL = "shell" + WEB_SEARCH_PREVIEW = "web_search_preview" + WEB_SEARCH_PREVIEW_2025_03_11 = "web_search_preview_2025_03_11" + + + class azure.ai.projects.models.ToolChoiceWebSearchPreview(ToolChoiceParam, discriminator='web_search_preview'): + type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolChoiceWebSearchPreview20250311(ToolChoiceParam, discriminator='web_search_preview_2025_03_11'): + type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolConfig(_Model): + additional_search_text: Optional[str] + pin: Optional[bool] @overload def __init__( self, *, - name: Union[str, TelephonyCallLifecycleEventName], - observed_at: datetime, - occurred_at: Optional[datetime] = ..., - outcome: Union[str, TelephonyCallLifecycleEventOutcome], - provider_event_id: Optional[str] = ..., - provider_sequence: Optional[int] = ..., - provider_status_code: Optional[int] = ..., - provider_sub_code: Optional[int] = ..., - reason: Optional[Union[str, TelephonyCallLifecycleEventReason]] = ..., - source: Union[str, TelephonyCallLifecycleEventSource], - timestamp_source: Union[str, TelephonyCallTimestampSource] + additional_search_text: Optional[str] = ..., + pin: Optional[bool] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallLifecycleEventName(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AGENT_SESSION_CONNECT = "telephony.agent_session.connect" - BINDING_RESOLVE = "telephony.binding.resolve" - CALL_DISCONNECT = "telephony.call.disconnect" - CALL_HANGUP = "telephony.call.hangup" - CALL_TRANSFER = "telephony.call.transfer" - FIRST_AGENT_AUDIO = "telephony.media.first_agent_audio" - FIRST_CALLER_AUDIO = "telephony.media.first_caller_audio" - MEDIA_CONNECT = "telephony.media.connect" - PROVIDER_ANSWER = "telephony.provider.answer" - WEBHOOK_RECEIVED = "telephony.webhook.received" - WEBHOOK_VALIDATION = "telephony.webhook.validation" + class azure.ai.projects.models.ToolDescription(_Model): + description: Optional[str] + name: Optional[str] + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + name: Optional[str] = ... + ) -> None: ... - class azure.ai.projects.models.TelephonyCallLifecycleEventOutcome(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CANCELLED = "cancelled" - FAILED = "failed" - OBSERVED = "observed" - REJECTED = "rejected" - STARTED = "started" - SUCCEEDED = "succeeded" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallLifecycleEventReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ADMISSION_CHECK_FAILED = "admission_check_failed" - ADMISSION_REJECTED = "admission_rejected" - AGENT_SESSION_CONNECT_FAILED = "agent_session_connect_failed" - ANSWER_FAILED = "answer_failed" - BINDING_NOT_FOUND = "binding_not_found" - BINDING_SUSPENDED = "binding_suspended" - BRIDGE_CANCELLED = "bridge_cancelled" - BRIDGE_FAILED = "bridge_failed" - CREDENTIAL_RESOLUTION_FAILED = "credential_resolution_failed" - ENDPOINT_RESOLUTION_FAILED = "endpoint_resolution_failed" - INGRESS_SETUP_FAILED = "ingress_setup_failed" - INVALID_BINDING_CONFIGURATION = "invalid_binding_configuration" - INVALID_WEBHOOK_PAYLOAD = "invalid_webhook_payload" - LIVE_CALL_CONFLICT = "live_call_conflict" - LIVE_CALL_PERSISTENCE_FAILED = "live_call_persistence_failed" - MANAGED_HANGUP = "managed_hangup" - MANAGED_TRANSFER = "managed_transfer" - MANAGE_HANGUP_FAILED = "manage_hangup_failed" - MANAGE_TRANSFER_FAILED = "manage_transfer_failed" - MEDIA_STREAM_ENDED = "media_stream_ended" - PROVIDER_BUSY = "provider_busy" - PROVIDER_CANCELLED = "provider_cancelled" - PROVIDER_DISCONNECTED = "provider_disconnected" - PROVIDER_FAILED = "provider_failed" - PROVIDER_NO_ANSWER = "provider_no_answer" - PROVIDER_RESOURCE_MISMATCH = "provider_resource_mismatch" - PROVIDER_STREAM_ERROR = "provider_stream_error" - PROVIDER_STREAM_STOPPED = "provider_stream_stopped" - ROUTE_AGENT_MISMATCH = "route_agent_mismatch" - WEBHOOK_VALIDATION_FAILED = "webhook_validation_failed" + class azure.ai.projects.models.ToolDescriptionParam(TypedDict, total=False): + key "description": str + key "name": str + + + class azure.ai.projects.models.ToolProjectConnection(_Model): + project_connection_id: str + + @overload + def __init__( + self, + *, + project_connection_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolSearchExecutionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CLIENT = "client" + SERVER = "server" + + + class azure.ai.projects.models.ToolSearchToolParam(Tool, discriminator='tool_search'): + description: Optional[str] + execution: Optional[Union[str, ToolSearchExecutionType]] + parameters: Optional[EmptyModelParam] + type: Literal[ToolType.TOOL_SEARCH] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + execution: Optional[Union[str, ToolSearchExecutionType]] = ..., + parameters: Optional[EmptyModelParam] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolSearchToolboxTool(ToolboxTool, discriminator='toolbox_search'): + description: str + name: str + tool_configs: dict[str, ToolConfig] + type: Literal[ToolboxToolType.TOOLBOX_SEARCH] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + name: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + A2A_PREVIEW = "a2a_preview" + A2_A = "a2a" + APPLY_PATCH = "apply_patch" + AZURE_AI_SEARCH = "azure_ai_search" + AZURE_FUNCTION = "azure_function" + BING_CUSTOM_SEARCH_PREVIEW = "bing_custom_search_preview" + BING_GROUNDING = "bing_grounding" + BROWSER_AUTOMATION = "browser_automation" + BROWSER_AUTOMATION_PREVIEW = "browser_automation_preview" + CAPTURE_STRUCTURED_OUTPUTS = "capture_structured_outputs" + CODE_INTERPRETER = "code_interpreter" + COMPUTER = "computer" + COMPUTER_USE_PREVIEW = "computer_use_preview" + CUSTOM = "custom" + FABRIC_DATAAGENT_PREVIEW = "fabric_dataagent_preview" + FABRIC_IQ_PREVIEW = "fabric_iq_preview" + FILE_SEARCH = "file_search" + FUNCTION = "function" + GITHUB_COPILOT_TOOLSET_PREVIEW = "github_copilot_toolset_preview" + IMAGE_GENERATION = "image_generation" + LOCAL_SHELL = "local_shell" + MCP = "mcp" + MEMORY_SEARCH_PREVIEW = "memory_search_preview" + MICROSOFT_COPILOT_TOOLSET_PREVIEW = "microsoft_copilot_toolset_preview" + NAMESPACE = "namespace" + OPENAPI = "openapi" + PROGRAMMATIC_TOOL_CALLING = "programmatic_tool_calling" + SHAREPOINT_GROUNDING_PREVIEW = "sharepoint_grounding_preview" + SHELL = "shell" + TOOLBOX_SEARCH_PREVIEW = "toolbox_search_preview" + TOOL_SEARCH = "tool_search" + WEB_IQ_PREVIEW = "web_iq_preview" + WEB_SEARCH = "web_search" + WEB_SEARCH_PREVIEW = "web_search_preview" + WORK_IQ_PREVIEW = "work_iq_preview" + + + class azure.ai.projects.models.ToolUseFineTuningDataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='tool_use'): + max_samples: int + model_options: DataGenerationModelOptions + train_split: float + type: Literal[DataGenerationJobType.TOOL_USE] + + @overload + def __init__( + self, + *, + max_samples: int, + model_options: Optional[DataGenerationModelOptions] = ..., + train_split: Optional[float] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolboxObject(_Model): + default_version: str + id: str + name: str + updated_at: datetime + versions: ToolboxVersions + + @overload + def __init__( + self, + *, + default_version: str, + id: str, + name: str, + updated_at: datetime, + versions: ToolboxVersions + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolboxPolicies(_Model): + rai_config: Optional[RaiConfig] + + @overload + def __init__( + self, + *, + rai_config: Optional[RaiConfig] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallLifecycleEventSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): - GATEWAY = "gateway" - TEAMS_PHONE_EXTENSIBILITY = "teams_phone_extensibility" - TWILIO = "twilio" - VOICE_AGENT = "voice_agent" + class azure.ai.projects.models.ToolboxSearchPreviewToolboxTool(ToolboxTool, discriminator='toolbox_search_preview'): + description: str + name: str + tool_configs: dict[str, ToolConfig] + type: Literal[ToolboxToolType.TOOLBOX_SEARCH_PREVIEW] + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + name: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ... + ) -> None: ... - class azure.ai.projects.models.TelephonyCallPhase(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ADMITTED = "admitted" - AGENT_SESSION_READY = "agent_session_ready" - ANSWERED = "answered" - ANSWERING = "answering" - BRIDGING = "bridging" - COMPLETED = "completed" - FAILED = "failed" - MANAGING = "managing" - MEDIA_CONNECTED = "media_connected" - RECEIVED = "received" - REJECTED = "rejected" - VALIDATED = "validated" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallRecord(_Model): - agent_session_ready_at: Optional[datetime] - answered_at: Optional[datetime] - caller_number: Optional[str] - duration_ms: Optional[timedelta] - end_reason: Optional[Union[str, TelephonyCallEndReason]] - ended_at: Optional[datetime] - events: list[TelephonyCallLifecycleEvent] - events_truncated: bool - id: str - media_connected_at: Optional[datetime] - phase: Union[str, TelephonyCallPhase] - provider: Union[str, TelephonyProvider] - provider_call_id: Optional[str] - provider_message: Optional[str] - provider_number: Optional[str] - provider_status_code: Optional[int] - provider_sub_code: Optional[int] - started_at: datetime - status: Union[str, TelephonyCallStatus] - timing: TelephonyCallTiming - trace: Optional[TelephonyCallTrace] + class azure.ai.projects.models.ToolboxShellContainerAutoEnvironment(ToolboxShellEnvironment, discriminator='container_auto'): + file_ids: Optional[list[str]] + memory_limit: Optional[Union[str, ContainerMemoryLimit]] + network_policy: Optional[ToolboxShellNetworkPolicy] + skills: Optional[list[ContainerSkill]] + type: Literal["container_auto"] @overload def __init__( self, *, - agent_session_ready_at: Optional[datetime] = ..., - answered_at: Optional[datetime] = ..., - caller_number: Optional[str] = ..., - duration_ms: Optional[timedelta] = ..., - end_reason: Optional[Union[str, TelephonyCallEndReason]] = ..., - ended_at: Optional[datetime] = ..., - events: list[TelephonyCallLifecycleEvent], - events_truncated: bool, - id: str, - media_connected_at: Optional[datetime] = ..., - phase: Union[str, TelephonyCallPhase], - provider: Union[str, TelephonyProvider], - provider_call_id: Optional[str] = ..., - provider_message: Optional[str] = ..., - provider_number: Optional[str] = ..., - provider_status_code: Optional[int] = ..., - provider_sub_code: Optional[int] = ..., - started_at: datetime, - status: Union[str, TelephonyCallStatus], - timing: TelephonyCallTiming, - trace: Optional[TelephonyCallTrace] = ... + file_ids: Optional[list[str]] = ..., + memory_limit: Optional[Union[str, ContainerMemoryLimit]] = ..., + network_policy: Optional[ToolboxShellNetworkPolicy] = ..., + skills: Optional[list[ContainerSkill]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - FAILED = "failed" - IN_PROGRESS = "in_progress" - SUCCESS = "success" - - - class azure.ai.projects.models.TelephonyCallSummary(_Model): - agent_session_ready_at: Optional[datetime] - answered_at: Optional[datetime] - caller_number: Optional[str] - duration_ms: Optional[timedelta] - end_reason: Optional[Union[str, TelephonyCallEndReason]] - ended_at: Optional[datetime] - id: str - media_connected_at: Optional[datetime] - phase: Union[str, TelephonyCallPhase] - provider: Union[str, TelephonyProvider] - provider_call_id: Optional[str] - provider_message: Optional[str] - provider_number: Optional[str] - provider_status_code: Optional[int] - provider_sub_code: Optional[int] - started_at: datetime - status: Union[str, TelephonyCallStatus] + class azure.ai.projects.models.ToolboxShellContainerReferenceEnvironment(ToolboxShellEnvironment, discriminator='container_reference'): + container_id: str + type: Literal["container_reference"] @overload def __init__( self, *, - agent_session_ready_at: Optional[datetime] = ..., - answered_at: Optional[datetime] = ..., - caller_number: Optional[str] = ..., - duration_ms: Optional[timedelta] = ..., - end_reason: Optional[Union[str, TelephonyCallEndReason]] = ..., - ended_at: Optional[datetime] = ..., - id: str, - media_connected_at: Optional[datetime] = ..., - phase: Union[str, TelephonyCallPhase], - provider: Union[str, TelephonyProvider], - provider_call_id: Optional[str] = ..., - provider_message: Optional[str] = ..., - provider_number: Optional[str] = ..., - provider_status_code: Optional[int] = ..., - provider_sub_code: Optional[int] = ..., - started_at: datetime, - status: Union[str, TelephonyCallStatus] + container_id: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallTimestampSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): - DERIVED = "derived" - GATEWAY = "gateway" - PROVIDER = "provider" + class azure.ai.projects.models.ToolboxShellEnvironment(_Model): + type: str + @overload + def __init__( + self, + *, + type: str + ) -> None: ... - class azure.ai.projects.models.TelephonyCallTiming(_Model): - admitted_at: Optional[datetime] - agent_session_ready_at: Optional[datetime] - answer_requested_at: Optional[datetime] - answered_at: Optional[datetime] - duration_basis: Optional[Union[str, TelephonyCallDurationBasis]] - ended_at: Optional[datetime] - first_agent_audio_at: Optional[datetime] - first_caller_audio_at: Optional[datetime] - media_connected_at: Optional[datetime] - received_at: Optional[datetime] - timestamp_source: Union[str, TelephonyCallTimestampSource] - validated_at: Optional[datetime] + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolboxShellNetworkPolicy(_Model): + type: str @overload def __init__( self, *, - admitted_at: Optional[datetime] = ..., - agent_session_ready_at: Optional[datetime] = ..., - answer_requested_at: Optional[datetime] = ..., - answered_at: Optional[datetime] = ..., - duration_basis: Optional[Union[str, TelephonyCallDurationBasis]] = ..., - ended_at: Optional[datetime] = ..., - first_agent_audio_at: Optional[datetime] = ..., - first_caller_audio_at: Optional[datetime] = ..., - media_connected_at: Optional[datetime] = ..., - received_at: Optional[datetime] = ..., - timestamp_source: Union[str, TelephonyCallTimestampSource], - validated_at: Optional[datetime] = ... + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallTrace(_Model): - conversation_id: Optional[str] - mode: Optional[Union[str, TelephonyCallTraceMode]] - root_span_id: Optional[str] - status: Union[str, TelephonyCallTraceStatus] - trace_id: Optional[str] + class azure.ai.projects.models.ToolboxShellNetworkPolicyDisabled(ToolboxShellNetworkPolicy, discriminator='disabled'): + type: Literal["disabled"] + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.ToolboxSkill(_Model): + type: str @overload def __init__( self, *, - conversation_id: Optional[str] = ..., - mode: Optional[Union[str, TelephonyCallTraceMode]] = ..., - root_span_id: Optional[str] = ..., - status: Union[str, TelephonyCallTraceStatus], - trace_id: Optional[str] = ... + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyCallTraceMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): - LIVE = "live" - POST_CALL = "post_call" + class azure.ai.projects.models.ToolboxSkillReference(ToolboxSkill, discriminator='skill_reference'): + name: str + type: Literal["skill_reference"] + version: Optional[str] + @overload + def __init__( + self, + *, + name: str, + version: Optional[str] = ... + ) -> None: ... - class azure.ai.projects.models.TelephonyCallTraceStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AVAILABLE = "available" - EMITTING = "emitting" - FAILED = "failed" - NOT_APPLICABLE = "not_applicable" - NOT_RECORDED = "not_recorded" - PENDING = "pending" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyOutboundDestination(_Model): - type: Union[str, TelephonyOutboundDestinationType] - value: str + class azure.ai.projects.models.ToolboxTool(_Model): + description: Optional[str] + name: Optional[str] + tool_configs: Optional[dict[str, ToolConfig]] + type: str @overload def __init__( self, *, - type: Union[str, TelephonyOutboundDestinationType], - value: str + description: Optional[str] = ..., + name: Optional[str] = ..., + tool_configs: Optional[dict[str, ToolConfig]] = ..., + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyOutboundDestinationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - PHONE_NUMBER = "phone_number" + class azure.ai.projects.models.ToolboxToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + A2A_PREVIEW = "a2a_preview" + A2_A = "a2a" + AZURE_AI_SEARCH = "azure_ai_search" + BROWSER_AUTOMATION = "browser_automation" + BROWSER_AUTOMATION_PREVIEW = "browser_automation_preview" + CODE_INTERPRETER = "code_interpreter" + FABRIC_IQ_PREVIEW = "fabric_iq_preview" + FILE_SEARCH = "file_search" + MCP = "mcp" + OPENAPI = "openapi" + REMINDER_PREVIEW = "reminder_preview" + SHELL = "shell" + TOOLBOX_SEARCH = "toolbox_search" + TOOLBOX_SEARCH_PREVIEW = "toolbox_search_preview" + WEB_IQ_PREVIEW = "web_iq_preview" + WEB_SEARCH = "web_search" + WORK_IQ_PREVIEW = "work_iq_preview" - class azure.ai.projects.models.TelephonyOutboundFixedIntervalRetryPolicy(TelephonyOutboundRetryPolicy, discriminator='fixed_interval'): - interval: timedelta - max_attempts: int - type: Literal[TelephonyOutboundRetryPolicyType.FIXED_INTERVAL] + class azure.ai.projects.models.ToolboxVersionObject(_Model): + created_at: datetime + description: Optional[str] + id: str + metadata: dict[str, str] + name: str + policies: Optional[ToolboxPolicies] + skills: Optional[list[ToolboxSkill]] + tools: list[ToolboxTool] + version: str @overload def __init__( self, *, - interval: timedelta, - max_attempts: Optional[int] = ... + created_at: datetime, + description: Optional[str] = ..., + id: str, + metadata: dict[str, str], + name: str, + policies: Optional[ToolboxPolicies] = ..., + skills: Optional[list[ToolboxSkill]] = ..., + tools: list[ToolboxTool], + version: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyOutboundRetryPolicy(_Model): - max_attempts: Optional[int] - type: str + class azure.ai.projects.models.ToolboxVersions(_Model): + latest: ToolboxVersionObject @overload def __init__( self, *, - max_attempts: Optional[int] = ..., - type: str + latest: ToolboxVersionObject ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyOutboundRetryPolicyType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - FIXED_INTERVAL = "fixed_interval" - - - class azure.ai.projects.models.TelephonyProvider(str, Enum, metaclass=CaseInsensitiveEnumMeta): - TEAMS_PHONE_EXTENSIBILITY = "teams_phone_extensibility" - TWILIO = "twilio" - - - class azure.ai.projects.models.TelephonyTransferDestination(_Model): - kind: str + class azure.ai.projects.models.TracesDataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='traces'): + max_samples: Optional[int] + model_options: DataGenerationModelOptions + redact_private_content: Optional[bool] + train_split: float + type: Literal[DataGenerationJobType.TRACES] @overload def __init__( self, *, - kind: str + max_samples: Optional[int] = ..., + model_options: Optional[DataGenerationModelOptions] = ..., + redact_private_content: Optional[bool] = ..., + train_split: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyTransferDestinationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - PSTN = "pstn" - SIP = "sip" - TEAMS = "teams" - - - class azure.ai.projects.models.TelephonyTransferTarget(_Model): + class azure.ai.projects.models.TracesDataGenerationJobSource(DataGenerationJobSource, discriminator='traces'): + agent_id: Optional[str] + agent_name: Optional[str] + agent_version: Optional[str] description: str - destination: TelephonyTransferDestination - name: str + end_time: Optional[datetime] + start_time: datetime + trace_ids: Optional[list[str]] + type: Literal[DataGenerationJobSourceType.TRACES] @overload def __init__( self, *, - description: str, - destination: TelephonyTransferDestination, - name: str + agent_id: Optional[str] = ..., + agent_name: Optional[str] = ..., + agent_version: Optional[str] = ..., + description: Optional[str] = ..., + end_time: Optional[datetime] = ..., + start_time: datetime, + trace_ids: Optional[list[str]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TelephonyTransferTargets(_Model): - transfer_targets: list[TelephonyTransferTarget] + class azure.ai.projects.models.TracesEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator='traces'): + agent_id: Optional[str] + agent_name: Optional[str] + agent_version: Optional[str] + description: Optional[str] + end_time: Optional[datetime] + start_time: datetime + type: Literal[EvaluatorGenerationJobSourceType.TRACES] @overload def __init__( self, *, - transfer_targets: list[TelephonyTransferTarget] + agent_id: Optional[str] = ..., + agent_name: Optional[str] = ..., + agent_version: Optional[str] = ..., + description: Optional[str] = ..., + end_time: Optional[datetime] = ..., + start_time: datetime ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TestingCriterionAzureAIEvaluator(TypedDict, total=False): - key "data_mapping": Dict[str, str] - key "evaluator_name": Required[str] - key "evaluator_version": str - key "initialization_parameters": Dict[str, Any] - key "name": Required[str] - key "type": Required[Literal["azure_ai_evaluator"]] + class azure.ai.projects.models.TracesPreviewEvalRunDataSource(TypedDict, total=False): + key "agent_id": str + key "agent_name": str + key "end_time": datetime + key "ingestion_delay_seconds": int + key "lookback_hours": int + key "max_traces": int + key "trace_ids": List[str] + key "type": Required[Literal["azure_ai_traces_preview"]] - class azure.ai.projects.models.TextResponseFormat(_Model): - type: str + class azure.ai.projects.models.TranscriptTextUsageDuration(CreateTranscriptionResponseJsonUsage, discriminator='duration'): + seconds: timedelta + type: Literal[CreateTranscriptionResponseJsonUsageType.DURATION] @overload def __init__( self, *, - type: str + seconds: timedelta ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TextResponseFormatConfigurationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - JSON_OBJECT = "json_object" - JSON_SCHEMA = "json_schema" - TEXT = "text" - - - class azure.ai.projects.models.TextResponseFormatJsonObject(TextResponseFormat, discriminator='json_object'): - type: Literal[TextResponseFormatConfigurationType.JSON_OBJECT] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.TextResponseFormatJsonSchema(TextResponseFormat, discriminator='json_schema'): - description: Optional[str] - name: str - schema: dict[str, Any] - strict: Optional[bool] - type: Literal[TextResponseFormatConfigurationType.JSON_SCHEMA] + class azure.ai.projects.models.TranscriptTextUsageTokens(CreateTranscriptionResponseJsonUsage, discriminator='tokens'): + input_token_details: Optional[TranscriptTextUsageTokensInputTokenDetails] + input_tokens: int + output_tokens: int + total_tokens: int + type: Literal[CreateTranscriptionResponseJsonUsageType.TOKENS] @overload def __init__( self, *, - description: Optional[str] = ..., - name: str, - schema: dict[str, Any], - strict: Optional[bool] = ... + input_token_details: Optional[TranscriptTextUsageTokensInputTokenDetails] = ..., + input_tokens: int, + output_tokens: int, + total_tokens: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TextResponseFormatText(TextResponseFormat, discriminator='text'): - type: Literal[TextResponseFormatConfigurationType.TEXT] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.TimerRoutineTrigger(RoutineTrigger, discriminator='timer'): - at: Optional[datetime] - type: Literal[RoutineTriggerType.TIMER] + class azure.ai.projects.models.TranscriptTextUsageTokensInputTokenDetails(_Model): + audio_tokens: Optional[int] + text_tokens: Optional[int] @overload def __init__( self, *, - at: Optional[datetime] = ... + audio_tokens: Optional[int] = ..., + text_tokens: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.Tool(_Model): - type: str + class azure.ai.projects.models.TranscriptionLanguage(_Model): + code: str @overload def __init__( self, *, - type: str + code: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceAllowed(ToolChoiceParam, discriminator='allowed_tools'): - mode: Literal["auto", "required"] - tools: list[dict[str, Any]] - type: Literal[ToolChoiceParamType.ALLOWED_TOOLS] + class azure.ai.projects.models.TreatmentEffectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CHANGED = "Changed" + DEGRADED = "Degraded" + IMPROVED = "Improved" + INCONCLUSIVE = "Inconclusive" + TOO_FEW_SAMPLES = "TooFewSamples" + + + class azure.ai.projects.models.Trigger(_Model): + type: str @overload def __init__( self, *, - mode: Literal["auto", "required"], - tools: list[dict[str, Any]] + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceCodeInterpreter(ToolChoiceParam, discriminator='code_interpreter'): - type: Literal[ToolChoiceParamType.CODE_INTERPRETER] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.TriggerType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CRON = "Cron" + ONE_TIME = "OneTime" + RECURRENCE = "Recurrence" - class azure.ai.projects.models.ToolChoiceComputer(ToolChoiceParam, discriminator='computer'): - type: Literal[ToolChoiceParamType.COMPUTER] + class azure.ai.projects.models.TwilioTelephonyBinding(TelephonyBinding, discriminator='twilio'): + connection_name: str + id: str + incoming_call_url: str + label: str + phone_number: str + provider: Literal[TelephonyProvider.TWILIO] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + connection_name: str, + label: Optional[str] = ..., + phone_number: str + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceComputerUse(ToolChoiceParam, discriminator='computer_use'): - type: Literal[ToolChoiceParamType.COMPUTER_USE] + class azure.ai.projects.models.TwilioTelephonyBindingListItem(TelephonyBindingListItem, discriminator='twilio'): + connection_name: str + etag: str + id: str + incoming_call_url: str + label: str + phone_number: str + provider: Literal[TelephonyProvider.TWILIO] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + connection_name: str, + id: str, + incoming_call_url: str, + label: Optional[str] = ..., + phone_number: str + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceComputerUsePreview(ToolChoiceParam, discriminator='computer_use_preview'): - type: Literal[ToolChoiceParamType.COMPUTER_USE_PREVIEW] - - @overload - def __init__(self) -> None: ... + class azure.ai.projects.models.UpdateMemoriesLROPoller(LROPoller[MemoryStoreUpdateCompletedResult]): + property superseded_by: Optional[str] # Read-only + property update_id: str # Read-only - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + @classmethod + def from_continuation_token( + cls, + polling_method: PollingMethod[MemoryStoreUpdateCompletedResult], + continuation_token: str, + **kwargs: Any + ) -> UpdateMemoriesLROPoller: ... - class azure.ai.projects.models.ToolChoiceCustom(ToolChoiceParam, discriminator='custom'): - name: str - type: Literal[ToolChoiceParamType.CUSTOM] + class azure.ai.projects.models.UpdateModelVersionRequest(_Model): + description: Optional[str] + tags: Optional[dict[str, str]] @overload def __init__( self, *, - name: str + description: Optional[str] = ..., + tags: Optional[dict[str, str]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceFileSearch(ToolChoiceParam, discriminator='file_search'): - type: Literal[ToolChoiceParamType.FILE_SEARCH] + class azure.ai.projects.models.UpdateTelephonyBindingRequest(_Model): + allowed_calling_numbers: Optional[list[str]] + connection_name: Optional[str] + label: Optional[str] + phone_number: Optional[str] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + allowed_calling_numbers: Optional[list[str]] = ..., + connection_name: Optional[str] = ..., + label: Optional[str] = ..., + phone_number: Optional[str] = ... + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceFunction(ToolChoiceParam, discriminator='function'): - name: str - type: Literal[ToolChoiceParamType.FUNCTION] + class azure.ai.projects.models.UpdateToolboxRequest(_Model): + default_version: str @overload def __init__( self, *, - name: str + default_version: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceImageGeneration(ToolChoiceParam, discriminator='image_generation'): - type: Literal[ToolChoiceParamType.IMAGE_GENERATION] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.UserConversationSimulationAudioEffect(str, Enum, metaclass=CaseInsensitiveEnumMeta): + BACKGROUND_TV = "background_tv" + CROWD_CHATTER = "crowd_chatter" + METRO_STATION = "metro_station" + STREET_TRAFFIC = "street_traffic" + TELEPHONIC_VOICE = "telephonic_voice" - class azure.ai.projects.models.ToolChoiceMCP(ToolChoiceParam, discriminator='mcp'): - name: Optional[str] - server_label: str - type: Literal[ToolChoiceParamType.MCP] + class azure.ai.projects.models.UserConversationSimulationAudioEffectsConfiguration(_Model): + effects: Optional[list[Union[str, UserConversationSimulationAudioEffect]]] + volume_percentage: Optional[int] @overload def __init__( self, *, - name: Optional[str] = ..., - server_label: str + effects: Optional[list[Union[str, UserConversationSimulationAudioEffect]]] = ..., + volume_percentage: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceOptions(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AUTO = "auto" - NONE = "none" - REQUIRED = "required" - - - class azure.ai.projects.models.ToolChoiceParam(_Model): - type: str + class azure.ai.projects.models.UserConversationSimulationConfiguration(_Model): + audio_effects: Optional[UserConversationSimulationAudioEffectsConfiguration] + conversation_repetitions: Optional[int] + desired_num_turns: Optional[int] + max_num_turns: Optional[int] + user_behavior: Optional[UserConversationSimulationUserBehaviorConfiguration] @overload def __init__( self, *, - type: str + audio_effects: Optional[UserConversationSimulationAudioEffectsConfiguration] = ..., + conversation_repetitions: Optional[int] = ..., + desired_num_turns: Optional[int] = ..., + max_num_turns: Optional[int] = ..., + user_behavior: Optional[UserConversationSimulationUserBehaviorConfiguration] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - ALLOWED_TOOLS = "allowed_tools" - APPLY_PATCH = "apply_patch" - CODE_INTERPRETER = "code_interpreter" - COMPUTER = "computer" - COMPUTER_USE = "computer_use" - COMPUTER_USE_PREVIEW = "computer_use_preview" - CUSTOM = "custom" - FILE_SEARCH = "file_search" - FUNCTION = "function" - IMAGE_GENERATION = "image_generation" - MCP = "mcp" - PROGRAMMATIC_TOOL_CALLING = "programmatic_tool_calling" - SHELL = "shell" - WEB_SEARCH_PREVIEW = "web_search_preview" - WEB_SEARCH_PREVIEW_2025_03_11 = "web_search_preview_2025_03_11" - - - class azure.ai.projects.models.ToolChoiceWebSearchPreview(ToolChoiceParam, discriminator='web_search_preview'): - type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW] + class azure.ai.projects.models.UserConversationSimulationDefaultInterruptionConfiguration(UserConversationSimulationInterruptionConfiguration, discriminator='default'): + type: Literal["default"] @overload def __init__(self) -> None: ... @@ -14400,1535 +18550,1624 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolChoiceWebSearchPreview20250311(ToolChoiceParam, discriminator='web_search_preview_2025_03_11'): - type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11] + class azure.ai.projects.models.UserConversationSimulationInterruptionConfiguration(_Model): + type: str @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + type: str + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolConfig(_Model): - additional_search_text: Optional[str] - pin: Optional[bool] + class azure.ai.projects.models.UserConversationSimulationTestCase(_Model): + simulation_configuration: Optional[UserConversationSimulationConfiguration] + test_case_category: Optional[str] + test_case_description: Optional[str] + test_case_id: Optional[str] @overload def __init__( self, *, - additional_search_text: Optional[str] = ..., - pin: Optional[bool] = ... + simulation_configuration: Optional[UserConversationSimulationConfiguration] = ..., + test_case_category: Optional[str] = ..., + test_case_description: Optional[str] = ..., + test_case_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolDescription(_Model): - description: Optional[str] - name: Optional[str] + class azure.ai.projects.models.UserConversationSimulationUserBehaviorConfiguration(_Model): + interruption: Optional[UserConversationSimulationInterruptionConfiguration] @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ... + interruption: Optional[UserConversationSimulationInterruptionConfiguration] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolDescriptionParam(TypedDict, total=False): - key "description": str - key "name": str + class azure.ai.projects.models.UserProfileMemoryItem(MemoryItem, discriminator='user_profile'): + content: str + kind: Literal[MemoryItemKind.USER_PROFILE] + memory_id: str + scope: str + updated_at: datetime + + @overload + def __init__( + self, + *, + content: str, + memory_id: str, + scope: str, + updated_at: datetime + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolProjectConnection(_Model): - project_connection_id: str + class azure.ai.projects.models.VersionIndicator(_Model): + type: str @overload def __init__( self, *, - project_connection_id: str + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolSearchExecutionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CLIENT = "client" - SERVER = "server" + class azure.ai.projects.models.VersionIndicatorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + VERSION_REF = "version_ref" - class azure.ai.projects.models.ToolSearchToolParam(Tool, discriminator='tool_search'): - description: Optional[str] - execution: Optional[Union[str, ToolSearchExecutionType]] - parameters: Optional[EmptyModelParam] - type: Literal[ToolType.TOOL_SEARCH] + class azure.ai.projects.models.VersionRefIndicator(VersionIndicator, discriminator='version_ref'): + agent_version: str + type: Literal[VersionIndicatorType.VERSION_REF] @overload def __init__( self, *, - description: Optional[str] = ..., - execution: Optional[Union[str, ToolSearchExecutionType]] = ..., - parameters: Optional[EmptyModelParam] = ... + agent_version: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolSearchToolboxTool(ToolboxTool, discriminator='toolbox_search'): - description: str - name: str - tool_configs: dict[str, ToolConfig] - type: Literal[ToolboxToolType.TOOLBOX_SEARCH] + class azure.ai.projects.models.VersionSelectionRule(_Model): + agent_version: str + type: str @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ... + agent_version: str, + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - A2A_PREVIEW = "a2a_preview" - A2_A = "a2a" - APPLY_PATCH = "apply_patch" - AZURE_AI_SEARCH = "azure_ai_search" - AZURE_FUNCTION = "azure_function" - BING_CUSTOM_SEARCH_PREVIEW = "bing_custom_search_preview" - BING_GROUNDING = "bing_grounding" - BROWSER_AUTOMATION = "browser_automation" - BROWSER_AUTOMATION_PREVIEW = "browser_automation_preview" - CAPTURE_STRUCTURED_OUTPUTS = "capture_structured_outputs" - CODE_INTERPRETER = "code_interpreter" - COMPUTER = "computer" - COMPUTER_USE_PREVIEW = "computer_use_preview" - CUSTOM = "custom" - FABRIC_DATAAGENT_PREVIEW = "fabric_dataagent_preview" - FABRIC_IQ_PREVIEW = "fabric_iq_preview" - FILE_SEARCH = "file_search" - FUNCTION = "function" - GITHUB_COPILOT_TOOLSET_PREVIEW = "github_copilot_toolset_preview" - IMAGE_GENERATION = "image_generation" - LOCAL_SHELL = "local_shell" - MCP = "mcp" - MEMORY_SEARCH_PREVIEW = "memory_search_preview" - MICROSOFT_COPILOT_TOOLSET_PREVIEW = "microsoft_copilot_toolset_preview" - NAMESPACE = "namespace" - OPENAPI = "openapi" - PROGRAMMATIC_TOOL_CALLING = "programmatic_tool_calling" - SHAREPOINT_GROUNDING_PREVIEW = "sharepoint_grounding_preview" - SHELL = "shell" - TOOLBOX_SEARCH_PREVIEW = "toolbox_search_preview" - TOOL_SEARCH = "tool_search" - WEB_IQ_PREVIEW = "web_iq_preview" - WEB_SEARCH = "web_search" - WEB_SEARCH_PREVIEW = "web_search_preview" - WORK_IQ_PREVIEW = "work_iq_preview" - - - class azure.ai.projects.models.ToolUseFineTuningDataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='tool_use'): - max_samples: int - model_options: DataGenerationModelOptions - train_split: float - type: Literal[DataGenerationJobType.TOOL_USE] + class azure.ai.projects.models.VersionSelector(_Model): + version_selection_rules: list[VersionSelectionRule] @overload def __init__( self, *, - max_samples: int, - model_options: Optional[DataGenerationModelOptions] = ..., - train_split: Optional[float] = ... + version_selection_rules: list[VersionSelectionRule] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxObject(_Model): - default_version: str - id: str - name: str - updated_at: datetime - versions: ToolboxVersions + class azure.ai.projects.models.VersionSelectorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FIXED_RATIO = "FixedRatio" + + + class azure.ai.projects.models.VoiceAgentAnimationConfig(_Model): + model_name: Optional[str] + outputs: Optional[list[Union[str, VoiceAgentAnimationOutputType]]] @overload - def __init__( - self, - *, - default_version: str, - id: str, - name: str, - updated_at: datetime, - versions: ToolboxVersions + def __init__( + self, + *, + model_name: Optional[str] = ..., + outputs: Optional[list[Union[str, VoiceAgentAnimationOutputType]]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxPolicies(_Model): - rai_config: Optional[RaiConfig] + class azure.ai.projects.models.VoiceAgentAnimationOutputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + BLENDSHAPES = "blendshapes" + VISEME_ID = "viseme_id" + + + class azure.ai.projects.models.VoiceAgentAudioConfig(_Model): + input: Optional[VoiceAgentAudioInputConfig] + output: Optional[VoiceAgentAudioOutputConfig] @overload def __init__( self, *, - rai_config: Optional[RaiConfig] = ... + input: Optional[VoiceAgentAudioInputConfig] = ..., + output: Optional[VoiceAgentAudioOutputConfig] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxSearchPreviewToolboxTool(ToolboxTool, discriminator='toolbox_search_preview'): - description: str - name: str - tool_configs: dict[str, ToolConfig] - type: Literal[ToolboxToolType.TOOLBOX_SEARCH_PREVIEW] + class azure.ai.projects.models.VoiceAgentAudioInputConfig(_Model): + echo_cancellation: Optional[VoiceAgentEchoCancellation] + format: Optional[RealtimeAudioFormats] + noise_reduction: Optional[VoiceAgentNoiseReduction] + transcription: Optional[VoiceAgentInputTranscription] + turn_detection: Optional[VoiceAgentTurnDetectionConfig] @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ... + echo_cancellation: Optional[VoiceAgentEchoCancellation] = ..., + format: Optional[RealtimeAudioFormats] = ..., + noise_reduction: Optional[VoiceAgentNoiseReduction] = ..., + transcription: Optional[VoiceAgentInputTranscription] = ..., + turn_detection: Optional[VoiceAgentTurnDetectionConfig] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxShellContainerAutoEnvironment(ToolboxShellEnvironment, discriminator='container_auto'): - file_ids: Optional[list[str]] - memory_limit: Optional[Union[str, ContainerMemoryLimit]] - network_policy: Optional[ToolboxShellNetworkPolicy] - skills: Optional[list[ContainerSkill]] - type: Literal["container_auto"] + class azure.ai.projects.models.VoiceAgentAudioOutputConfig(VoiceAgentVoiceConfig): + custom_lexicon_url: str + custom_text_normalization_url: str + custom_voice_endpoint_id: str + format: Optional[RealtimeAudioFormats] + output_audio_timestamp_types: Optional[list[Union[str, VoiceAgentAudioTimestampType]]] + personal_voice_model: str + pitch: str + prefer_locales: list[str] + speed: float + style: str + voice: str + voice_locale: str + voice_temperature: float + voice_type: Union[str, VoiceType] + volume: str @overload def __init__( self, *, - file_ids: Optional[list[str]] = ..., - memory_limit: Optional[Union[str, ContainerMemoryLimit]] = ..., - network_policy: Optional[ToolboxShellNetworkPolicy] = ..., - skills: Optional[list[ContainerSkill]] = ... + custom_lexicon_url: Optional[str] = ..., + custom_text_normalization_url: Optional[str] = ..., + custom_voice_endpoint_id: Optional[str] = ..., + format: Optional[RealtimeAudioFormats] = ..., + output_audio_timestamp_types: Optional[list[Union[str, VoiceAgentAudioTimestampType]]] = ..., + personal_voice_model: Optional[str] = ..., + pitch: Optional[str] = ..., + prefer_locales: Optional[list[str]] = ..., + speed: Optional[float] = ..., + style: Optional[str] = ..., + voice: Optional[str] = ..., + voice_locale: Optional[str] = ..., + voice_temperature: Optional[float] = ..., + voice_type: Optional[Union[str, VoiceType]] = ..., + volume: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxShellContainerReferenceEnvironment(ToolboxShellEnvironment, discriminator='container_reference'): - container_id: str - type: Literal["container_reference"] + class azure.ai.projects.models.VoiceAgentAudioTimestampType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + WORD = "word" + + + class azure.ai.projects.models.VoiceAgentAvatarConfig(_Model): + character: str + customized: Optional[bool] + model: Optional[str] + output_audit_audio: Optional[bool] + output_protocol: Optional[Union[str, VoiceAgentAvatarOutputProtocol]] + scene: Optional[VoiceAgentAvatarScene] + style: Optional[str] + type: Union[str, VoiceAgentAvatarType] + video: Optional[VoiceAgentAvatarVideoParams] @overload def __init__( self, *, - container_id: str + character: str, + customized: Optional[bool] = ..., + model: Optional[str] = ..., + output_audit_audio: Optional[bool] = ..., + output_protocol: Optional[Union[str, VoiceAgentAvatarOutputProtocol]] = ..., + scene: Optional[VoiceAgentAvatarScene] = ..., + style: Optional[str] = ..., + type: Union[str, VoiceAgentAvatarType], + video: Optional[VoiceAgentAvatarVideoParams] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxShellEnvironment(_Model): - type: str + class azure.ai.projects.models.VoiceAgentAvatarIceServer(_Model): + credential: Optional[str] + urls: list[str] + username: Optional[str] @overload def __init__( self, *, - type: str + credential: Optional[str] = ..., + urls: list[str], + username: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxShellNetworkPolicy(_Model): - type: str + class azure.ai.projects.models.VoiceAgentAvatarOutputProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): + WEBRTC = "webrtc" + WEBSOCKET = "websocket" + + + class azure.ai.projects.models.VoiceAgentAvatarScene(_Model): + amplitude: Optional[float] + position_x: Optional[float] + position_y: Optional[float] + rotation_x: Optional[float] + rotation_y: Optional[float] + rotation_z: Optional[float] + zoom: Optional[float] @overload def __init__( self, *, - type: str + amplitude: Optional[float] = ..., + position_x: Optional[float] = ..., + position_y: Optional[float] = ..., + rotation_x: Optional[float] = ..., + rotation_y: Optional[float] = ..., + rotation_z: Optional[float] = ..., + zoom: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxShellNetworkPolicyDisabled(ToolboxShellNetworkPolicy, discriminator='disabled'): - type: Literal["disabled"] + class azure.ai.projects.models.VoiceAgentAvatarType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + PHOTO_AVATAR = "photo_avatar" + VIDEO_AVATAR = "video_avatar" + + + class azure.ai.projects.models.VoiceAgentAvatarVideoBackground(_Model): + color: Optional[str] + image_url: Optional[str] @overload - def __init__(self) -> None: ... + def __init__( + self, + *, + color: Optional[str] = ..., + image_url: Optional[str] = ... + ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxSkill(_Model): - type: str + class azure.ai.projects.models.VoiceAgentAvatarVideoCrop(_Model): + bottom_right: list[int] + top_left: list[int] @overload def __init__( self, *, - type: str + bottom_right: list[int], + top_left: list[int] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxSkillReference(ToolboxSkill, discriminator='skill_reference'): - name: str - type: Literal["skill_reference"] - version: Optional[str] + class azure.ai.projects.models.VoiceAgentAvatarVideoParams(_Model): + background: Optional[VoiceAgentAvatarVideoBackground] + bitrate: Optional[int] + crop: Optional[VoiceAgentAvatarVideoCrop] + gop_size: Optional[int] + resolution: Optional[VoiceAgentAvatarVideoResolution] @overload def __init__( self, *, - name: str, - version: Optional[str] = ... + background: Optional[VoiceAgentAvatarVideoBackground] = ..., + bitrate: Optional[int] = ..., + crop: Optional[VoiceAgentAvatarVideoCrop] = ..., + gop_size: Optional[int] = ..., + resolution: Optional[VoiceAgentAvatarVideoResolution] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxTool(_Model): - description: Optional[str] - name: Optional[str] - tool_configs: Optional[dict[str, ToolConfig]] - type: str + class azure.ai.projects.models.VoiceAgentAvatarVideoResolution(_Model): + height: int + width: int @overload def __init__( self, *, - description: Optional[str] = ..., - name: Optional[str] = ..., - tool_configs: Optional[dict[str, ToolConfig]] = ..., - type: str + height: int, + width: int ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - A2A_PREVIEW = "a2a_preview" - A2_A = "a2a" - AZURE_AI_SEARCH = "azure_ai_search" - BROWSER_AUTOMATION = "browser_automation" - BROWSER_AUTOMATION_PREVIEW = "browser_automation_preview" - CODE_INTERPRETER = "code_interpreter" - FABRIC_IQ_PREVIEW = "fabric_iq_preview" - FILE_SEARCH = "file_search" - MCP = "mcp" - OPENAPI = "openapi" - REMINDER_PREVIEW = "reminder_preview" - SHELL = "shell" - TOOLBOX_SEARCH = "toolbox_search" - TOOLBOX_SEARCH_PREVIEW = "toolbox_search_preview" - WEB_IQ_PREVIEW = "web_iq_preview" - WEB_SEARCH = "web_search" - WORK_IQ_PREVIEW = "work_iq_preview" - - - class azure.ai.projects.models.ToolboxVersionObject(_Model): - created_at: datetime - description: Optional[str] - id: str - metadata: dict[str, str] - name: str - policies: Optional[ToolboxPolicies] - skills: Optional[list[ToolboxSkill]] - tools: list[ToolboxTool] - version: str + class azure.ai.projects.models.VoiceAgentAzureSemanticVadEnTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='azure_semantic_vad_en'): + auto_truncate: bool + create_response: Optional[bool] + end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] + idle_timeout_ms: Optional[timedelta] + interrupt_response: Optional[bool] + prefix_padding_ms: Optional[timedelta] + remove_filler_words: Optional[bool] + silence_duration_ms: Optional[timedelta] + speech_duration_ms: Optional[timedelta] + threshold: Optional[float] + type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_EN] @overload def __init__( self, *, - created_at: datetime, - description: Optional[str] = ..., - id: str, - metadata: dict[str, str], - name: str, - policies: Optional[ToolboxPolicies] = ..., - skills: Optional[list[ToolboxSkill]] = ..., - tools: list[ToolboxTool], - version: str + auto_truncate: Optional[bool] = ..., + create_response: Optional[bool] = ..., + end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] = ..., + idle_timeout_ms: Optional[timedelta] = ..., + interrupt_response: Optional[bool] = ..., + prefix_padding_ms: Optional[timedelta] = ..., + remove_filler_words: Optional[bool] = ..., + silence_duration_ms: Optional[timedelta] = ..., + speech_duration_ms: Optional[timedelta] = ..., + threshold: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.ToolboxVersions(_Model): - latest: ToolboxVersionObject + class azure.ai.projects.models.VoiceAgentAzureSemanticVadMultilingualTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='azure_semantic_vad_multilingual'): + auto_truncate: bool + create_response: Optional[bool] + end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] + idle_timeout_ms: Optional[timedelta] + interrupt_response: Optional[bool] + languages: Optional[list[str]] + prefix_padding_ms: Optional[timedelta] + remove_filler_words: Optional[bool] + silence_duration_ms: Optional[timedelta] + speech_duration_ms: Optional[timedelta] + threshold: Optional[float] + type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_MULTILINGUAL] @overload def __init__( self, *, - latest: ToolboxVersionObject + auto_truncate: Optional[bool] = ..., + create_response: Optional[bool] = ..., + end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] = ..., + idle_timeout_ms: Optional[timedelta] = ..., + interrupt_response: Optional[bool] = ..., + languages: Optional[list[str]] = ..., + prefix_padding_ms: Optional[timedelta] = ..., + remove_filler_words: Optional[bool] = ..., + silence_duration_ms: Optional[timedelta] = ..., + speech_duration_ms: Optional[timedelta] = ..., + threshold: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TracesDataGenerationJobConfiguration(DataGenerationJobConfiguration, discriminator='traces'): - max_samples: Optional[int] - model_options: DataGenerationModelOptions - redact_private_content: Optional[bool] - train_split: float - type: Literal[DataGenerationJobType.TRACES] + class azure.ai.projects.models.VoiceAgentAzureSemanticVadTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='azure_semantic_vad'): + auto_truncate: bool + create_response: Optional[bool] + end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] + idle_timeout_ms: Optional[timedelta] + interrupt_response: Optional[bool] + languages: Optional[list[str]] + prefix_padding_ms: Optional[timedelta] + remove_filler_words: Optional[bool] + silence_duration_ms: Optional[timedelta] + speech_duration_ms: Optional[timedelta] + threshold: Optional[float] + type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD] @overload def __init__( self, *, - max_samples: Optional[int] = ..., - model_options: Optional[DataGenerationModelOptions] = ..., - redact_private_content: Optional[bool] = ..., - train_split: Optional[float] = ... + auto_truncate: Optional[bool] = ..., + create_response: Optional[bool] = ..., + end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] = ..., + idle_timeout_ms: Optional[timedelta] = ..., + interrupt_response: Optional[bool] = ..., + languages: Optional[list[str]] = ..., + prefix_padding_ms: Optional[timedelta] = ..., + remove_filler_words: Optional[bool] = ..., + silence_duration_ms: Optional[timedelta] = ..., + speech_duration_ms: Optional[timedelta] = ..., + threshold: Optional[float] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TracesDataGenerationJobSource(DataGenerationJobSource, discriminator='traces'): - agent_id: Optional[str] - agent_name: Optional[str] - agent_version: Optional[str] - description: str - end_time: Optional[datetime] - start_time: datetime - trace_ids: Optional[list[str]] - type: Literal[DataGenerationJobSourceType.TRACES] + class azure.ai.projects.models.VoiceAgentBaseDefinition(AgentDefinition, discriminator='voice'): + instructions: Optional[str] + kind: Literal[AgentKind.VOICE] + rai_config: RaiConfig + store: Optional[bool] + structured_inputs: Optional[dict[str, StructuredInputDefinition]] + sub_protocol: str @overload def __init__( self, *, - agent_id: Optional[str] = ..., - agent_name: Optional[str] = ..., - agent_version: Optional[str] = ..., - description: Optional[str] = ..., - end_time: Optional[datetime] = ..., - start_time: datetime, - trace_ids: Optional[list[str]] = ... + instructions: Optional[str] = ..., + rai_config: Optional[RaiConfig] = ..., + store: Optional[bool] = ..., + structured_inputs: Optional[dict[str, StructuredInputDefinition]] = ..., + sub_protocol: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TracesEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator='traces'): - agent_id: Optional[str] - agent_name: Optional[str] - agent_version: Optional[str] - description: Optional[str] - end_time: Optional[datetime] - start_time: datetime - type: Literal[EvaluatorGenerationJobSourceType.TRACES] + class azure.ai.projects.models.VoiceAgentClientEventRtcCallSdpCreate(RealtimeClientEvent, discriminator='rtc.call.sdp.create'): + event_id: Optional[str] + sdp_offer: str + session: Optional[VoiceAgentSessionUpdateConfig] + type: Literal[VoiceAgentClientEventTypeExtension.RTC_CALL_SDP_CREATE] @overload def __init__( self, *, - agent_id: Optional[str] = ..., - agent_name: Optional[str] = ..., - agent_version: Optional[str] = ..., - description: Optional[str] = ..., - end_time: Optional[datetime] = ..., - start_time: datetime + event_id: Optional[str] = ..., + sdp_offer: str, + session: Optional[VoiceAgentSessionUpdateConfig] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TracesPreviewEvalRunDataSource(TypedDict, total=False): - key "agent_id": str - key "agent_name": str - key "end_time": datetime - key "ingestion_delay_seconds": int - key "lookback_hours": int - key "max_traces": int - key "trace_ids": List[str] - key "type": Required[Literal["azure_ai_traces_preview"]] - - - class azure.ai.projects.models.TranscriptTextUsageDuration(CreateTranscriptionResponseJsonUsage, discriminator='duration'): - seconds: timedelta - type: Literal[CreateTranscriptionResponseJsonUsageType.DURATION] + class azure.ai.projects.models.VoiceAgentClientEventSessionAvatarConnect(RealtimeClientEvent, discriminator='session.avatar.connect'): + client_sdp: str + event_id: Optional[str] + type: Literal[VoiceAgentClientEventTypeExtension.SESSION_AVATAR_CONNECT] @overload def __init__( self, *, - seconds: timedelta + client_sdp: str, + event_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TranscriptTextUsageTokens(CreateTranscriptionResponseJsonUsage, discriminator='tokens'): - input_token_details: Optional[TranscriptTextUsageTokensInputTokenDetails] - input_tokens: int - output_tokens: int - total_tokens: int - type: Literal[CreateTranscriptionResponseJsonUsageType.TOKENS] + class azure.ai.projects.models.VoiceAgentClientEventSessionUpdate(_Model): + event_id: Optional[str] + session: VoiceAgentSessionUpdate + type: Literal[RealtimeClientEventType.SESSION_UPDATE] @overload def __init__( self, *, - input_token_details: Optional[TranscriptTextUsageTokensInputTokenDetails] = ..., - input_tokens: int, - output_tokens: int, - total_tokens: int + event_id: Optional[str] = ..., + session: VoiceAgentSessionUpdate, + type: Literal[RealtimeClientEventType.SESSION_UPDATE] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TranscriptTextUsageTokensInputTokenDetails(_Model): - audio_tokens: Optional[int] - text_tokens: Optional[int] - - @overload - def __init__( - self, - *, - audio_tokens: Optional[int] = ..., - text_tokens: Optional[int] = ... - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentClientEventTypeExtension(str, Enum, metaclass=CaseInsensitiveEnumMeta): + RTC_CALL_SDP_CREATE = "rtc.call.sdp.create" + SESSION_AVATAR_CONNECT = "session.avatar.connect" - class azure.ai.projects.models.TranscriptionLanguage(_Model): - code: str + class azure.ai.projects.models.VoiceAgentCollectDtmfStartArguments(_Model): + completion_mode: VoiceAgentDtmfCompletionMode + first_digit_timeout_seconds: Optional[int] + output_variable_name: Optional[str] + secret: bool + timeout_seconds: Optional[int] @overload def __init__( self, *, - code: str + completion_mode: VoiceAgentDtmfCompletionMode, + first_digit_timeout_seconds: Optional[int] = ..., + output_variable_name: Optional[str] = ..., + secret: bool, + timeout_seconds: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TreatmentEffectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CHANGED = "Changed" - DEGRADED = "Degraded" - IMPROVED = "Improved" - INCONCLUSIVE = "Inconclusive" - TOO_FEW_SAMPLES = "TooFewSamples" - - - class azure.ai.projects.models.Trigger(_Model): - type: str + class azure.ai.projects.models.VoiceAgentCollectDtmfSystemTool(VoiceAgentSystemTool, discriminator='collect_dtmf'): + description: str + name: Literal[VoiceAgentSystemToolName.COLLECT_DTMF] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] @overload def __init__( self, *, - type: str + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TriggerType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - CRON = "Cron" - ONE_TIME = "OneTime" - RECURRENCE = "Recurrence" - - - class azure.ai.projects.models.TwilioTelephonyBinding(TelephonyBinding, discriminator='twilio'): - connection_name: str - id: str - incoming_call_url: str - label: str - phone_number: str - provider: Literal[TelephonyProvider.TWILIO] - status: Union[str, TelephonyBindingStatus] + class azure.ai.projects.models.VoiceAgentCollectSmsStartArguments(_Model): + from_phone_number: str + output_variable_name: Optional[str] + secret: bool + timeout_seconds: Optional[int] @overload def __init__( self, *, - connection_name: str, - id: str, - incoming_call_url: str, - label: Optional[str] = ..., - phone_number: str, - status: Union[str, TelephonyBindingStatus] + from_phone_number: str, + output_variable_name: Optional[str] = ..., + secret: bool, + timeout_seconds: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.TwilioTelephonyBindingListItem(TelephonyBindingListItem, discriminator='twilio'): - connection_name: str - etag: str - id: str - incoming_call_url: str - label: str - phone_number: str - provider: Literal[TelephonyProvider.TWILIO] - status: Union[str, TelephonyBindingStatus] + class azure.ai.projects.models.VoiceAgentCollectSmsSystemTool(VoiceAgentSystemTool, discriminator='collect_sms'): + description: str + name: Literal[VoiceAgentSystemToolName.COLLECT_SMS] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] @overload def __init__( self, *, - connection_name: str, - id: str, - incoming_call_url: str, - label: Optional[str] = ..., - phone_number: str, - status: Union[str, TelephonyBindingStatus] + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UpdateMemoriesLROPoller(LROPoller[MemoryStoreUpdateCompletedResult]): - property superseded_by: Optional[str] # Read-only - property update_id: str # Read-only - - @classmethod - def from_continuation_token( - cls, - polling_method: PollingMethod[MemoryStoreUpdateCompletedResult], - continuation_token: str, - **kwargs: Any - ) -> UpdateMemoriesLROPoller: ... - - - class azure.ai.projects.models.UpdateModelVersionRequest(_Model): - description: Optional[str] - tags: Optional[dict[str, str]] + class azure.ai.projects.models.VoiceAgentCollectionStartArguments(_Model): + output_variable_name: Optional[str] + secret: bool + timeout_seconds: Optional[int] @overload def __init__( self, *, - description: Optional[str] = ..., - tags: Optional[dict[str, str]] = ... + output_variable_name: Optional[str] = ..., + secret: bool, + timeout_seconds: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UpdateTelephonyBindingRequest(_Model): - connection_name: Optional[str] - label: Optional[str] - phone_number: Optional[str] - status: Optional[Union[str, TelephonyBindingStatus]] + class azure.ai.projects.models.VoiceAgentConversationItemTypeExtension(str, Enum, metaclass=CaseInsensitiveEnumMeta): + SYSTEM_TOOL = "system_tool" + + + class azure.ai.projects.models.VoiceAgentDefinition(VoiceAgentBaseDefinition, discriminator='realtime'): + audio: Optional[VoiceAgentAudioConfig] + avatar: Optional[VoiceAgentAvatarConfig] + conversation_engine: Optional[VoiceConversationEngine] + greeting: Optional[VoiceAgentGreetingConfig] + include: Optional[list[Union[str, VoiceAgentSessionIncludeOption]]] + instructions: str + interim_response: Optional[VoiceAgentInterimResponseConfig] + kind: Union[str, azure.ai.projects.models.VOICE] + max_output_tokens: Optional[VoiceAgentMaxOutputTokens] + model: Optional[str] + model_type: Optional[Union[str, VoiceModelType]] + output_modalities: Optional[list[Union[str, VoiceOutputModality]]] + parallel_tool_calls: Optional[bool] + post_call: Optional[VoiceAgentPostCallConfig] + rai_config: RaiConfig + soundscape: Optional[VoiceAgentSoundscapeConfig] + store: bool + structured_inputs: dict[str, StructuredInputDefinition] + sub_protocol: Literal[VoiceAgentSubProtocol.REALTIME] + subagent_config: Optional[VoiceAgentSubagentConfig] + tool_choice: Optional[VoiceAgentToolChoice] + tools: Optional[list[VoiceAgentTool]] @overload def __init__( self, *, - connection_name: Optional[str] = ..., - label: Optional[str] = ..., - phone_number: Optional[str] = ..., - status: Optional[Union[str, TelephonyBindingStatus]] = ... + audio: Optional[VoiceAgentAudioConfig] = ..., + avatar: Optional[VoiceAgentAvatarConfig] = ..., + conversation_engine: Optional[VoiceConversationEngine] = ..., + greeting: Optional[VoiceAgentGreetingConfig] = ..., + include: Optional[list[Union[str, VoiceAgentSessionIncludeOption]]] = ..., + instructions: Optional[str] = ..., + interim_response: Optional[VoiceAgentInterimResponseConfig] = ..., + max_output_tokens: Optional[VoiceAgentMaxOutputTokens] = ..., + model: Optional[str] = ..., + model_type: Optional[Union[str, VoiceModelType]] = ..., + output_modalities: Optional[list[Union[str, VoiceOutputModality]]] = ..., + parallel_tool_calls: Optional[bool] = ..., + post_call: Optional[VoiceAgentPostCallConfig] = ..., + rai_config: Optional[RaiConfig] = ..., + soundscape: Optional[VoiceAgentSoundscapeConfig] = ..., + store: Optional[bool] = ..., + structured_inputs: Optional[dict[str, StructuredInputDefinition]] = ..., + subagent_config: Optional[VoiceAgentSubagentConfig] = ..., + tool_choice: Optional[VoiceAgentToolChoice] = ..., + tools: Optional[list[VoiceAgentTool]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UpdateToolboxRequest(_Model): - default_version: str + class azure.ai.projects.models.VoiceAgentDelegateSubagentConfig(VoiceAgentSubagentConfig, discriminator='delegate'): + subagent_type: Literal[VoiceAgentSubagentType.DELEGATE] + subagents: list[VoiceAgentSubagent] @overload def __init__( self, *, - default_version: str + subagents: list[VoiceAgentSubagent] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UserConversationSimulationAudioEffect(str, Enum, metaclass=CaseInsensitiveEnumMeta): - BACKGROUND_TV = "background_tv" - CROWD_CHATTER = "crowd_chatter" - METRO_STATION = "metro_station" - STREET_TRAFFIC = "street_traffic" - TELEPHONIC_VOICE = "telephonic_voice" - - - class azure.ai.projects.models.UserConversationSimulationAudioEffectsConfiguration(_Model): - effects: Optional[list[Union[str, UserConversationSimulationAudioEffect]]] - volume_percentage: Optional[int] + class azure.ai.projects.models.VoiceAgentDigitRecognitionSystemTool(VoiceAgentSystemTool, discriminator='digit_recognition'): + description: str + name: Literal[VoiceAgentSystemToolName.DIGIT_RECOGNITION] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] @overload def __init__( self, *, - effects: Optional[list[Union[str, UserConversationSimulationAudioEffect]]] = ..., - volume_percentage: Optional[int] = ... + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UserConversationSimulationConfiguration(_Model): - audio_effects: Optional[UserConversationSimulationAudioEffectsConfiguration] - conversation_repetitions: Optional[int] - desired_num_turns: Optional[int] - max_num_turns: Optional[int] - user_behavior: Optional[UserConversationSimulationUserBehaviorConfiguration] + class azure.ai.projects.models.VoiceAgentDtmfFixedLengthCompletionMode(_Model): + inter_digit_timeout_seconds: Optional[int] + length: Optional[int] + type: Literal["fixed_length"] @overload def __init__( self, *, - audio_effects: Optional[UserConversationSimulationAudioEffectsConfiguration] = ..., - conversation_repetitions: Optional[int] = ..., - desired_num_turns: Optional[int] = ..., - max_num_turns: Optional[int] = ..., - user_behavior: Optional[UserConversationSimulationUserBehaviorConfiguration] = ... + inter_digit_timeout_seconds: Optional[int] = ..., + length: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UserConversationSimulationDefaultInterruptionConfiguration(UserConversationSimulationInterruptionConfiguration, discriminator='default'): - type: Literal["default"] - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... - - - class azure.ai.projects.models.UserConversationSimulationInterruptionConfiguration(_Model): - type: str + class azure.ai.projects.models.VoiceAgentDtmfInterDigitSilenceCompletionMode(_Model): + inter_digit_timeout_seconds: Optional[int] + type: Literal["inter_digit_silence"] @overload def __init__( self, *, - type: str + inter_digit_timeout_seconds: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UserConversationSimulationTestCase(_Model): - simulation_configuration: Optional[UserConversationSimulationConfiguration] - test_case_category: Optional[str] - test_case_description: Optional[str] - test_case_id: Optional[str] + class azure.ai.projects.models.VoiceAgentDtmfTerminator(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ASTERISK = "*" + NUMBER_SIGN = "#" + + + class azure.ai.projects.models.VoiceAgentDtmfTerminatorCompletionMode(_Model): + inter_digit_timeout_seconds: Optional[int] + terminator: Union[str, VoiceAgentDtmfTerminator] + type: Literal["terminator"] @overload def __init__( self, *, - simulation_configuration: Optional[UserConversationSimulationConfiguration] = ..., - test_case_category: Optional[str] = ..., - test_case_description: Optional[str] = ..., - test_case_id: Optional[str] = ... + inter_digit_timeout_seconds: Optional[int] = ..., + terminator: Union[str, VoiceAgentDtmfTerminator] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UserConversationSimulationUserBehaviorConfiguration(_Model): - interruption: Optional[UserConversationSimulationInterruptionConfiguration] + class azure.ai.projects.models.VoiceAgentEchoCancellation(_Model): + channels: Optional[int] + reference_source: Optional[Union[str, VoiceAgentEchoCancellationReferenceSource]] + type: Literal["server_echo_cancellation"] @overload def __init__( self, *, - interruption: Optional[UserConversationSimulationInterruptionConfiguration] = ... + channels: Optional[int] = ..., + reference_source: Optional[Union[str, VoiceAgentEchoCancellationReferenceSource]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.UserProfileMemoryItem(MemoryItem, discriminator='user_profile'): - content: str - kind: Literal[MemoryItemKind.USER_PROFILE] - memory_id: str - scope: str - updated_at: datetime + class azure.ai.projects.models.VoiceAgentEchoCancellationReferenceSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CLIENT = "client" + SERVER = "server" + + + class azure.ai.projects.models.VoiceAgentEndConversationSystemTool(VoiceAgentSystemTool, discriminator='end_conversation'): + description: str + name: Literal[VoiceAgentSystemToolName.END_CONVERSATION] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] @overload def __init__( self, *, - content: str, - memory_id: str, - scope: str, - updated_at: datetime + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VersionIndicator(_Model): - type: str + class azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection(_Model): + model: Union[str, VoiceAgentEndOfUtteranceDetectionModel] + threshold_level: Optional[Union[str, VoiceAgentEndOfUtteranceThresholdLevel]] + timeout_ms: Optional[timedelta] @overload def __init__( self, *, - type: str + model: Union[str, VoiceAgentEndOfUtteranceDetectionModel], + threshold_level: Optional[Union[str, VoiceAgentEndOfUtteranceThresholdLevel]] = ..., + timeout_ms: Optional[timedelta] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VersionIndicatorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - VERSION_REF = "version_ref" + class azure.ai.projects.models.VoiceAgentEndOfUtteranceDetectionModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + SEMANTIC_DETECTION_V1 = "semantic_detection_v1" + SEMANTIC_DETECTION_V1_EN = "semantic_detection_v1_en" + SEMANTIC_DETECTION_V1_MULTILINGUAL = "semantic_detection_v1_multilingual" + SMART_END_OF_TURN_DETECTION = "smart_end_of_turn_detection" - class azure.ai.projects.models.VersionRefIndicator(VersionIndicator, discriminator='version_ref'): - agent_version: str - type: Literal[VersionIndicatorType.VERSION_REF] + class azure.ai.projects.models.VoiceAgentEndOfUtteranceThresholdLevel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DEFAULT = "default" + HIGH = "high" + LOW = "low" + MEDIUM = "medium" + + + class azure.ai.projects.models.VoiceAgentEventGridPostCallDestination(VoiceAgentPostCallDestination, discriminator='event_grid'): + connection_name: str + type: Literal[VoiceAgentPostCallDestinationType.EVENT_GRID] @overload def __init__( self, *, - agent_version: str + connection_name: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VersionSelectionRule(_Model): - agent_version: str - type: str + class azure.ai.projects.models.VoiceAgentFunctionTool(VoiceAgentTool, discriminator='function'): + description: Optional[str] + name: str + parameters: Optional[RealtimeFunctionToolParameters] + type: Literal[VoiceAgentToolType.FUNCTION] @overload def __init__( self, *, - agent_version: str, - type: str + description: Optional[str] = ..., + name: str, + parameters: Optional[RealtimeFunctionToolParameters] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VersionSelector(_Model): - version_selection_rules: list[VersionSelectionRule] + class azure.ai.projects.models.VoiceAgentGreetingConfig(_Model): + type: str @overload def __init__( self, *, - version_selection_rules: list[VersionSelectionRule] + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VersionSelectorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - FIXED_RATIO = "FixedRatio" + class azure.ai.projects.models.VoiceAgentGreetingMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LLM_GENERATED = "llm_generated" + TEMPLATE = "template" - class azure.ai.projects.models.VoiceAgentAnimationConfig(_Model): - model_name: Optional[str] - outputs: Optional[list[Union[str, VoiceAgentAnimationOutputType]]] + class azure.ai.projects.models.VoiceAgentHandoffAbortReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ERROR = "error" + USER_INTERRUPTION = "user_interruption" + + + class azure.ai.projects.models.VoiceAgentHandoffCondition(_Model): + cancel_on_interruption: Optional[bool] + condition: str + delay_ms: Optional[timedelta] + id: str + target: str + target_response: Optional[Union[str, VoiceAgentHandoffTargetResponse]] + transfer_message: Optional[str] @overload def __init__( self, *, - model_name: Optional[str] = ..., - outputs: Optional[list[Union[str, VoiceAgentAnimationOutputType]]] = ... + cancel_on_interruption: Optional[bool] = ..., + condition: str, + delay_ms: Optional[timedelta] = ..., + id: str, + target: str, + target_response: Optional[Union[str, VoiceAgentHandoffTargetResponse]] = ..., + transfer_message: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAnimationOutputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - BLENDSHAPES = "blendshapes" - VISEME_ID = "viseme_id" - - - class azure.ai.projects.models.VoiceAgentAudioConfig(_Model): - input: Optional[VoiceAgentAudioInputConfig] - output: Optional[VoiceAgentAudioOutputConfig] + class azure.ai.projects.models.VoiceAgentHandoffEdgeState(_Model): + cancel_on_interruption: Optional[bool] + delay_ms: Optional[timedelta] + id: str + source: str + target: str + target_response: Optional[Union[str, VoiceAgentHandoffTargetResponse]] + transfer_message: Optional[str] @overload def __init__( self, *, - input: Optional[VoiceAgentAudioInputConfig] = ..., - output: Optional[VoiceAgentAudioOutputConfig] = ... + cancel_on_interruption: Optional[bool] = ..., + delay_ms: Optional[timedelta] = ..., + id: str, + source: str, + target: str, + target_response: Optional[Union[str, VoiceAgentHandoffTargetResponse]] = ..., + transfer_message: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAudioInputConfig(_Model): - echo_cancellation: Optional[VoiceAgentEchoCancellation] - format: Optional[RealtimeAudioFormats] - noise_reduction: Optional[VoiceAgentNoiseReduction] - transcription: Optional[VoiceAgentInputTranscription] - turn_detection: Optional[VoiceAgentTurnDetectionConfig] + class azure.ai.projects.models.VoiceAgentHandoffNodeState(_Model): + display_description: str + id: str + implicit: Optional[bool] @overload def __init__( self, *, - echo_cancellation: Optional[VoiceAgentEchoCancellation] = ..., - format: Optional[RealtimeAudioFormats] = ..., - noise_reduction: Optional[VoiceAgentNoiseReduction] = ..., - transcription: Optional[VoiceAgentInputTranscription] = ..., - turn_detection: Optional[VoiceAgentTurnDetectionConfig] = ... + display_description: str, + id: str, + implicit: Optional[bool] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAudioOutputConfig(_Model): - custom_lexicon_url: Optional[str] - custom_text_normalization_url: Optional[str] - custom_voice_endpoint_id: Optional[str] - format: Optional[RealtimeAudioFormats] - output_audio_timestamp_types: Optional[list[Union[str, VoiceAgentAudioTimestampType]]] - personal_voice_model: Optional[str] - pitch: Optional[str] - prefer_locales: Optional[list[str]] - speed: Optional[float] - style: Optional[str] - voice: Optional[str] - voice_locale: Optional[str] - voice_temperature: Optional[float] - voice_type: Optional[Union[str, VoiceType]] - volume: Optional[str] + class azure.ai.projects.models.VoiceAgentHandoffPipelineFamily(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CASCADED = "cascaded" + REALTIME = "realtime" + + + class azure.ai.projects.models.VoiceAgentHandoffPolicy(_Model): + max_attempts: Optional[int] + max_transfers: Optional[int] @overload def __init__( self, *, - custom_lexicon_url: Optional[str] = ..., - custom_text_normalization_url: Optional[str] = ..., - custom_voice_endpoint_id: Optional[str] = ..., - format: Optional[RealtimeAudioFormats] = ..., - output_audio_timestamp_types: Optional[list[Union[str, VoiceAgentAudioTimestampType]]] = ..., - personal_voice_model: Optional[str] = ..., - pitch: Optional[str] = ..., - prefer_locales: Optional[list[str]] = ..., - speed: Optional[float] = ..., - style: Optional[str] = ..., - voice: Optional[str] = ..., - voice_locale: Optional[str] = ..., - voice_temperature: Optional[float] = ..., - voice_type: Optional[Union[str, VoiceType]] = ..., - volume: Optional[str] = ... + max_attempts: Optional[int] = ..., + max_transfers: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAudioTimestampType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - WORD = "word" + class azure.ai.projects.models.VoiceAgentHandoffReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HIGH = "high" + LOW = "low" + MEDIUM = "medium" + MINIMAL = "minimal" + NONE = "none" + XHIGH = "xhigh" - class azure.ai.projects.models.VoiceAgentAvatarConfig(_Model): - character: str - customized: Optional[bool] - model: Optional[str] - output_audit_audio: Optional[bool] - output_protocol: Optional[Union[str, VoiceAgentAvatarOutputProtocol]] - scene: Optional[VoiceAgentAvatarScene] - style: Optional[str] - type: Union[str, VoiceAgentAvatarType] - video: Optional[VoiceAgentAvatarVideoParams] + class azure.ai.projects.models.VoiceAgentHandoffState(_Model): + active_node_id: str + attempt_count: int + available_edge_ids: list[str] + edges: list[VoiceAgentHandoffEdgeState] + node_generation: int + nodes: list[VoiceAgentHandoffNodeState] + pipeline_family: Union[str, VoiceAgentHandoffPipelineFamily] + transfer_count: int + transfer_tool: VoiceAgentFunctionTool @overload def __init__( self, *, - character: str, - customized: Optional[bool] = ..., - model: Optional[str] = ..., - output_audit_audio: Optional[bool] = ..., - output_protocol: Optional[Union[str, VoiceAgentAvatarOutputProtocol]] = ..., - scene: Optional[VoiceAgentAvatarScene] = ..., - style: Optional[str] = ..., - type: Union[str, VoiceAgentAvatarType], - video: Optional[VoiceAgentAvatarVideoParams] = ... + active_node_id: str, + attempt_count: int, + available_edge_ids: list[str], + edges: list[VoiceAgentHandoffEdgeState], + node_generation: int, + nodes: list[VoiceAgentHandoffNodeState], + pipeline_family: Union[str, VoiceAgentHandoffPipelineFamily], + transfer_count: int, + transfer_tool: VoiceAgentFunctionTool ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAvatarIceServer(_Model): - credential: Optional[str] - urls: list[str] - username: Optional[str] + class azure.ai.projects.models.VoiceAgentHandoffTargetResponse(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUTO = "auto" + NONE = "none" + + + class azure.ai.projects.models.VoiceAgentHandoffVoiceAdaptation(_Model): + type: Literal["auto"] + + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + + class azure.ai.projects.models.VoiceAgentInlineSubagentConfig(VoiceAgentSubagentConfig, discriminator='inline'): + handoff_policy: Optional[VoiceAgentHandoffPolicy] + subagent_type: Literal[VoiceAgentSubagentType.INLINE] + subagents: list[InlineVoiceSubagent] @overload def __init__( self, *, - credential: Optional[str] = ..., - urls: list[str], - username: Optional[str] = ... + handoff_policy: Optional[VoiceAgentHandoffPolicy] = ..., + subagents: list[InlineVoiceSubagent] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAvatarOutputProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): - WEBRTC = "webrtc" - WEBSOCKET = "websocket" + class azure.ai.projects.models.VoiceAgentInputCollectionChannel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DTMF = "dtmf" + SMS = "sms" - class azure.ai.projects.models.VoiceAgentAvatarScene(_Model): - amplitude: Optional[float] - position_x: Optional[float] - position_y: Optional[float] - rotation_x: Optional[float] - rotation_y: Optional[float] - rotation_z: Optional[float] - zoom: Optional[float] + class azure.ai.projects.models.VoiceAgentInputCollectionStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ACCEPTED = "accepted" + BUSY = "busy" + CANCELLED = "cancelled" + COMPLETED = "completed" + DISPATCH_FAILED = "dispatch_failed" + EXPIRED = "expired" + FAILED = "failed" + INVALID_ARGUMENTS = "invalid_arguments" + INVALID_INPUT = "invalid_input" + LISTENING = "listening" + PROVIDER_ACCEPTED = "provider_accepted" + PROVIDER_FAILED_OR_UNSUPPORTED = "provider_failed_or_unsupported" + PROVIDER_NOT_EXECUTED = "provider_not_executed" + PROVIDER_RESULT_UNCERTAIN = "provider_result_uncertain" + STALE_COLLECTION = "stale_collection" + TRANSFER_NOT_ANSWERED = "transfer_not_answered" + UNSUPPORTED_CHANNEL = "unsupported_channel" + + + class azure.ai.projects.models.VoiceAgentInputTranscription(_Model): + custom_speech: Optional[dict[str, str]] + delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] + keywords: Optional[list[str]] + language: Optional[str] + languages: Optional[list[str]] + model: Union[str, VoiceAgentInputTranscriptionModel] + phrase_list: Optional[list[str]] + profanity_filter: Optional[Union[str, VoiceAgentProfanityFilterMode]] + prompt: Optional[str] @overload def __init__( self, *, - amplitude: Optional[float] = ..., - position_x: Optional[float] = ..., - position_y: Optional[float] = ..., - rotation_x: Optional[float] = ..., - rotation_y: Optional[float] = ..., - rotation_z: Optional[float] = ..., - zoom: Optional[float] = ... + custom_speech: Optional[dict[str, str]] = ..., + delay: Optional[Literal[minimal, low, medium, high, xhigh]] = ..., + keywords: Optional[list[str]] = ..., + language: Optional[str] = ..., + languages: Optional[list[str]] = ..., + model: Union[str, VoiceAgentInputTranscriptionModel], + phrase_list: Optional[list[str]] = ..., + profanity_filter: Optional[Union[str, VoiceAgentProfanityFilterMode]] = ..., + prompt: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAvatarType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - PHOTO_AVATAR = "photo_avatar" - VIDEO_AVATAR = "video_avatar" + class azure.ai.projects.models.VoiceAgentInputTranscriptionModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AZURE_SPEECH = "azure-speech" + AZURE_SPEECH_STREAMING = "azure-speech-streaming" + GPT4_O_MINI_TRANSCRIBE = "gpt-4o-mini-transcribe" + GPT4_O_TRANSCRIBE = "gpt-4o-transcribe" + GPT4_O_TRANSCRIBE_DIARIZE = "gpt-4o-transcribe-diarize" + GPT_LIVE_TRANSCRIBE = "gpt-live-transcribe" + GPT_REALTIME_WHISPER = "gpt-realtime-whisper" + GPT_TRANSCRIBE = "gpt-transcribe" + MAI_TRANSCRIBE = "mai-transcribe" + WHISPER1 = "whisper-1" - class azure.ai.projects.models.VoiceAgentAvatarVideoBackground(_Model): - color: Optional[str] - image_url: Optional[str] + class azure.ai.projects.models.VoiceAgentInterimResponseConfig(_Model): + latency_threshold_ms: Optional[timedelta] + triggers: Optional[list[Union[str, VoiceAgentInterimResponseTrigger]]] + type: str @overload def __init__( self, *, - color: Optional[str] = ..., - image_url: Optional[str] = ... + latency_threshold_ms: Optional[timedelta] = ..., + triggers: Optional[list[Union[str, VoiceAgentInterimResponseTrigger]]] = ..., + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAvatarVideoCrop(_Model): - bottom_right: list[int] - top_left: list[int] + class azure.ai.projects.models.VoiceAgentInterimResponseTrigger(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LATENCY = "latency" + TOOL = "tool" - @overload - def __init__( - self, - *, - bottom_right: list[int], - top_left: list[int] - ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentInterimResponseType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LLM_INTERIM_RESPONSE = "llm_interim_response" + STATIC_INTERIM_RESPONSE = "static_interim_response" - class azure.ai.projects.models.VoiceAgentAvatarVideoParams(_Model): - background: Optional[VoiceAgentAvatarVideoBackground] - bitrate: Optional[int] - crop: Optional[VoiceAgentAvatarVideoCrop] - gop_size: Optional[int] - resolution: Optional[VoiceAgentAvatarVideoResolution] + class azure.ai.projects.models.VoiceAgentLanguageDetectionArguments(_Model): + language: str + reason: str @overload def __init__( self, *, - background: Optional[VoiceAgentAvatarVideoBackground] = ..., - bitrate: Optional[int] = ..., - crop: Optional[VoiceAgentAvatarVideoCrop] = ..., - gop_size: Optional[int] = ..., - resolution: Optional[VoiceAgentAvatarVideoResolution] = ... + language: str, + reason: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAvatarVideoResolution(_Model): - height: int - width: int + class azure.ai.projects.models.VoiceAgentLanguageDetectionSystemTool(VoiceAgentSystemTool, discriminator='language_detection'): + description: str + name: Literal[VoiceAgentSystemToolName.LANGUAGE_DETECTION] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] @overload def __init__( self, *, - height: int, - width: int + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAzureSemanticVadEnTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='azure_semantic_vad_en'): - auto_truncate: bool - create_response: Optional[bool] - end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] - idle_timeout_ms: Optional[timedelta] - interrupt_response: Optional[bool] - prefix_padding_ms: Optional[timedelta] - remove_filler_words: Optional[bool] - silence_duration_ms: Optional[timedelta] - speech_duration_ms: Optional[timedelta] - threshold: Optional[float] - type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_EN] + class azure.ai.projects.models.VoiceAgentLiveClientDelegation(VoiceAgentLiveDelegation, discriminator='client'): + acknowledgement_delay_ms: Optional[int] + type: Literal[VoiceAgentLiveDelegationType.CLIENT] @overload def __init__( self, *, - auto_truncate: Optional[bool] = ..., - create_response: Optional[bool] = ..., - end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] = ..., - idle_timeout_ms: Optional[timedelta] = ..., - interrupt_response: Optional[bool] = ..., - prefix_padding_ms: Optional[timedelta] = ..., - remove_filler_words: Optional[bool] = ..., - silence_duration_ms: Optional[timedelta] = ..., - speech_duration_ms: Optional[timedelta] = ..., - threshold: Optional[float] = ... + acknowledgement_delay_ms: Optional[int] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAzureSemanticVadMultilingualTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='azure_semantic_vad_multilingual'): - auto_truncate: bool - create_response: Optional[bool] - end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] - idle_timeout_ms: Optional[timedelta] - interrupt_response: Optional[bool] - languages: Optional[list[str]] - prefix_padding_ms: Optional[timedelta] - remove_filler_words: Optional[bool] - silence_duration_ms: Optional[timedelta] - speech_duration_ms: Optional[timedelta] - threshold: Optional[float] - type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_MULTILINGUAL] + class azure.ai.projects.models.VoiceAgentLiveClientDelegationConversationItem(VoiceAgentLiveDelegationConversationItem, discriminator='client'): + commentary: Optional[str] + created_at: datetime + id: str + response_id: str + target: Literal[VoiceAgentLiveDelegationTarget.CLIENT] + thinking: Optional[str] + type: Union[str, azure.ai.projects.models.DELEGATION] @overload def __init__( self, *, - auto_truncate: Optional[bool] = ..., - create_response: Optional[bool] = ..., - end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] = ..., - idle_timeout_ms: Optional[timedelta] = ..., - interrupt_response: Optional[bool] = ..., - languages: Optional[list[str]] = ..., - prefix_padding_ms: Optional[timedelta] = ..., - remove_filler_words: Optional[bool] = ..., - silence_duration_ms: Optional[timedelta] = ..., - speech_duration_ms: Optional[timedelta] = ..., - threshold: Optional[float] = ... + commentary: Optional[str] = ..., + created_at: datetime, + id: str, + response_id: Optional[str] = ..., + thinking: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentAzureSemanticVadTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='azure_semantic_vad'): - auto_truncate: bool - create_response: Optional[bool] - end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] - idle_timeout_ms: Optional[timedelta] - interrupt_response: Optional[bool] - languages: Optional[list[str]] - prefix_padding_ms: Optional[timedelta] - remove_filler_words: Optional[bool] - silence_duration_ms: Optional[timedelta] - speech_duration_ms: Optional[timedelta] - threshold: Optional[float] - type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD] + class azure.ai.projects.models.VoiceAgentLiveConversation(_Model): + completed_at: Optional[datetime] + created_at: datetime + id: str + last_error: Optional[ApiError] + metadata: Optional[dict[str, str]] + object: Literal["conversation"] + status: Union[str, VoiceConversationStatus] + usage: Optional[LiveSessionUsage] @overload def __init__( self, *, - auto_truncate: Optional[bool] = ..., - create_response: Optional[bool] = ..., - end_of_utterance_detection: Optional[VoiceAgentEndOfUtteranceDetection] = ..., - idle_timeout_ms: Optional[timedelta] = ..., - interrupt_response: Optional[bool] = ..., - languages: Optional[list[str]] = ..., - prefix_padding_ms: Optional[timedelta] = ..., - remove_filler_words: Optional[bool] = ..., - silence_duration_ms: Optional[timedelta] = ..., - speech_duration_ms: Optional[timedelta] = ..., - threshold: Optional[float] = ... + completed_at: Optional[datetime] = ..., + created_at: datetime, + id: str, + last_error: Optional[ApiError] = ..., + metadata: Optional[dict[str, str]] = ..., + status: Union[str, VoiceConversationStatus], + usage: Optional[LiveSessionUsage] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentClientEventRtcCallSdpCreate(RealtimeClientEvent, discriminator='rtc.call.sdp.create'): - event_id: Optional[str] - sdp_offer: str - session: Optional[VoiceAgentSessionUpdateConfig] - type: Literal[RealtimeClientEventType.RTC_CALL_SDP_CREATE] + class azure.ai.projects.models.VoiceAgentLiveConversationItem(_Model): + id: str + type: str @overload def __init__( self, *, - event_id: Optional[str] = ..., - sdp_offer: str, - session: Optional[VoiceAgentSessionUpdateConfig] = ... + id: str, + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentClientEventSessionAvatarConnect(RealtimeClientEvent, discriminator='session.avatar.connect'): - client_sdp: str - event_id: Optional[str] - type: Literal[RealtimeClientEventType.SESSION_AVATAR_CONNECT] + class azure.ai.projects.models.VoiceAgentLiveConversationItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DELEGATION = "delegation" + INPUT = "input" + OUTPUT = "output" + + + class azure.ai.projects.models.VoiceAgentLiveDefinition(VoiceAgentBaseDefinition, discriminator='live'): + audio: Optional[LiveInitialSessionAudioParam] + delegation: Optional[VoiceAgentLiveDelegation] + greeting: Optional[VoiceAgentTemplateGreetingConfig] + instructions: str + kind: Union[str, azure.ai.projects.models.VOICE] + model: str + model_type: Literal[VoiceModelType.SELF_DEPLOYED] + rai_config: RaiConfig + store: bool + structured_inputs: dict[str, StructuredInputDefinition] + sub_protocol: Literal[VoiceAgentSubProtocol.LIVE] @overload def __init__( self, *, - client_sdp: str, - event_id: Optional[str] = ... + audio: Optional[LiveInitialSessionAudioParam] = ..., + delegation: Optional[VoiceAgentLiveDelegation] = ..., + greeting: Optional[VoiceAgentTemplateGreetingConfig] = ..., + instructions: Optional[str] = ..., + model: str, + model_type: Literal[VoiceModelType.SELF_DEPLOYED], + rai_config: Optional[RaiConfig] = ..., + store: Optional[bool] = ..., + structured_inputs: Optional[dict[str, StructuredInputDefinition]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentClientEventSessionUpdate(_Model): - event_id: Optional[str] - session: VoiceAgentSessionUpdate - type: Literal[RealtimeClientEventType.SESSION_UPDATE] + class azure.ai.projects.models.VoiceAgentLiveDelegation(_Model): + type: str @overload def __init__( self, *, - event_id: Optional[str] = ..., - session: VoiceAgentSessionUpdate, - type: Literal[RealtimeClientEventType.SESSION_UPDATE] + type: str ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentDefinition(AgentDefinition, discriminator='voice'): - audio: Optional[VoiceAgentAudioConfig] - avatar: Optional[VoiceAgentAvatarConfig] - conversation_engine: Optional[VoiceConversationEngine] - greeting: Optional[VoiceAgentGreetingConfig] - include: Optional[list[Union[str, VoiceAgentSessionIncludeOption]]] - instructions: Optional[str] - interim_response: Optional[VoiceAgentInterimResponseConfig] - kind: Literal[AgentKind.VOICE] - max_output_tokens: Optional[VoiceAgentMaxOutputTokens] - model: Optional[str] - model_type: Optional[Union[str, VoiceModelType]] - output_modalities: Optional[list[Union[str, VoiceOutputModality]]] - parallel_tool_calls: Optional[bool] - rai_config: RaiConfig - soundscape: Optional[VoiceAgentSoundscapeConfig] - store: Optional[bool] - structured_inputs: Optional[dict[str, StructuredInputDefinition]] - subagent_config: Optional[VoiceAgentSubagentConfig] - tool_choice: Optional[VoiceAgentToolChoice] - tools: Optional[list[VoiceAgentTool]] + class azure.ai.projects.models.VoiceAgentLiveDelegationConversationItem(VoiceAgentLiveConversationItem, discriminator='delegation'): + created_at: datetime + id: str + response_id: Optional[str] + target: str + type: Literal[VoiceAgentLiveConversationItemType.DELEGATION] + + @overload + def __init__( + self, + *, + created_at: datetime, + id: str, + response_id: Optional[str] = ..., + target: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentLiveDelegationItem(_Model): + id: str + response_id: Optional[str] + target: Union[str, VoiceAgentLiveDelegationTarget] + type: Literal["delegation"] @overload def __init__( self, *, - audio: Optional[VoiceAgentAudioConfig] = ..., - avatar: Optional[VoiceAgentAvatarConfig] = ..., - conversation_engine: Optional[VoiceConversationEngine] = ..., - greeting: Optional[VoiceAgentGreetingConfig] = ..., - include: Optional[list[Union[str, VoiceAgentSessionIncludeOption]]] = ..., - instructions: Optional[str] = ..., - interim_response: Optional[VoiceAgentInterimResponseConfig] = ..., - max_output_tokens: Optional[VoiceAgentMaxOutputTokens] = ..., - model: Optional[str] = ..., - model_type: Optional[Union[str, VoiceModelType]] = ..., - output_modalities: Optional[list[Union[str, VoiceOutputModality]]] = ..., - parallel_tool_calls: Optional[bool] = ..., - rai_config: Optional[RaiConfig] = ..., - soundscape: Optional[VoiceAgentSoundscapeConfig] = ..., - store: Optional[bool] = ..., - structured_inputs: Optional[dict[str, StructuredInputDefinition]] = ..., - subagent_config: Optional[VoiceAgentSubagentConfig] = ..., - tool_choice: Optional[VoiceAgentToolChoice] = ..., - tools: Optional[list[VoiceAgentTool]] = ... + id: str, + response_id: Optional[str] = ..., + target: Union[str, VoiceAgentLiveDelegationTarget] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentEchoCancellation(_Model): - channels: Optional[int] - reference_source: Optional[Union[str, VoiceAgentEchoCancellationReferenceSource]] - type: Literal["server_echo_cancellation"] + class azure.ai.projects.models.VoiceAgentLiveDelegationResultItem(_Model): + commentary: Optional[str] + thinking: Optional[str] @overload def __init__( self, *, - channels: Optional[int] = ..., - reference_source: Optional[Union[str, VoiceAgentEchoCancellationReferenceSource]] = ... + commentary: Optional[str] = ..., + thinking: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentEchoCancellationReferenceSource(str, Enum, metaclass=CaseInsensitiveEnumMeta): + class azure.ai.projects.models.VoiceAgentLiveDelegationStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CANCELLED = "cancelled" + COMPLETED = "completed" + FAILED = "failed" + INCOMPLETE = "incomplete" + IN_PROGRESS = "in_progress" + + + class azure.ai.projects.models.VoiceAgentLiveDelegationTarget(str, Enum, metaclass=CaseInsensitiveEnumMeta): CLIENT = "client" - SERVER = "server" + FOUNDRY_MANAGED_AGENT = "foundry_managed_agent" + RESPONSES = "responses" - class azure.ai.projects.models.VoiceAgentEndConversationSystemTool(VoiceAgentSystemTool, discriminator='end_conversation'): - description: str - name: Literal[VoiceAgentSystemToolName.END_CONVERSATION] - type: str + class azure.ai.projects.models.VoiceAgentLiveDelegationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CLIENT = "client" + FOUNDRY_MANAGED_AGENT = "foundry_managed_agent" + RESPONSES = "responses" + + + class azure.ai.projects.models.VoiceAgentLiveFoundryManagedAgentDelegationItem(VoiceAgentLiveDelegationConversationItem, discriminator='foundry_managed_agent'): + agent_name: str + agent_version: str + backend_conversation_id: Optional[str] + created_at: datetime + delegation_context: Optional[str] + id: str + offset_ms: timedelta + output: list[VoiceAgentLiveDelegationResultItem] + response_id: str + status: Union[str, VoiceAgentLiveDelegationStatus] + target: Literal[VoiceAgentLiveDelegationTarget.FOUNDRY_MANAGED_AGENT] + type: Union[str, azure.ai.projects.models.DELEGATION] @overload def __init__( self, *, - description: Optional[str] = ... + agent_name: str, + agent_version: str, + backend_conversation_id: Optional[str] = ..., + created_at: datetime, + delegation_context: Optional[str] = ..., + id: str, + offset_ms: timedelta, + output: list[VoiceAgentLiveDelegationResultItem], + response_id: Optional[str] = ..., + status: Union[str, VoiceAgentLiveDelegationStatus] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection(_Model): - model: Union[str, VoiceAgentEndOfUtteranceDetectionModel] - threshold_level: Optional[Union[str, VoiceAgentEndOfUtteranceThresholdLevel]] - timeout_ms: Optional[timedelta] + class azure.ai.projects.models.VoiceAgentLiveInputConversationItem(VoiceAgentLiveConversationItem, discriminator='input'): + audio: Optional[VoiceAudioItem] + id: str + transcription: Optional[str] + type: Literal[VoiceAgentLiveConversationItemType.INPUT] @overload def __init__( self, *, - model: Union[str, VoiceAgentEndOfUtteranceDetectionModel], - threshold_level: Optional[Union[str, VoiceAgentEndOfUtteranceThresholdLevel]] = ..., - timeout_ms: Optional[timedelta] = ... + audio: Optional[VoiceAudioItem] = ..., + id: str, + transcription: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentEndOfUtteranceDetectionModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): - SEMANTIC_DETECTION_V1 = "semantic_detection_v1" - SEMANTIC_DETECTION_V1_EN = "semantic_detection_v1_en" - SEMANTIC_DETECTION_V1_MULTILINGUAL = "semantic_detection_v1_multilingual" - SMART_END_OF_TURN_DETECTION = "smart_end_of_turn_detection" + class azure.ai.projects.models.VoiceAgentLiveManagedAgentDelegation(VoiceAgentLiveDelegation, discriminator='foundry_managed_agent'): + agent_name: str + agent_version: Optional[str] + type: Literal[VoiceAgentLiveDelegationType.FOUNDRY_MANAGED_AGENT] + @overload + def __init__( + self, + *, + agent_name: str, + agent_version: Optional[str] = ... + ) -> None: ... - class azure.ai.projects.models.VoiceAgentEndOfUtteranceThresholdLevel(str, Enum, metaclass=CaseInsensitiveEnumMeta): - DEFAULT = "default" - HIGH = "high" - LOW = "low" - MEDIUM = "medium" + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentFunctionTool(VoiceAgentTool, discriminator='function'): - description: Optional[str] - name: str - parameters: Optional[RealtimeFunctionToolParameters] - type: Literal["function"] + class azure.ai.projects.models.VoiceAgentLiveOutputConversationItem(VoiceAgentLiveConversationItem, discriminator='output'): + audio: Optional[VoiceAudioItem] + id: str + transcription: Optional[str] + type: Literal[VoiceAgentLiveConversationItemType.OUTPUT] @overload def __init__( self, *, - description: Optional[str] = ..., - name: str, - parameters: Optional[RealtimeFunctionToolParameters] = ... + audio: Optional[VoiceAudioItem] = ..., + id: str, + transcription: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentGreetingConfig(_Model): - type: str + class azure.ai.projects.models.VoiceAgentLiveResponsesDelegation(VoiceAgentLiveDelegation, discriminator='responses'): + acknowledgement_delay_ms: Optional[int] + responses: LiveResponsesDelegationSettingsInputParam + type: Literal[VoiceAgentLiveDelegationType.RESPONSES] @overload def __init__( self, *, - type: str + acknowledgement_delay_ms: Optional[int] = ..., + responses: LiveResponsesDelegationSettingsInputParam ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentInputTranscription(_Model): - custom_speech: Optional[dict[str, str]] - delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] - keywords: Optional[list[str]] - language: Optional[str] - languages: Optional[list[str]] - model: Union[str, VoiceAgentInputTranscriptionModel] - phrase_list: Optional[list[str]] - profanity_filter: Optional[Union[str, VoiceAgentProfanityFilterMode]] - prompt: Optional[str] + class azure.ai.projects.models.VoiceAgentLiveResponsesDelegationConversationItem(VoiceAgentLiveDelegationConversationItem, discriminator='responses'): + created_at: datetime + id: str + output: Optional[str] + response_id: str + target: Literal[VoiceAgentLiveDelegationTarget.RESPONSES] + type: Union[str, azure.ai.projects.models.DELEGATION] @overload def __init__( self, *, - custom_speech: Optional[dict[str, str]] = ..., - delay: Optional[Literal[minimal, low, medium, high, xhigh]] = ..., - keywords: Optional[list[str]] = ..., - language: Optional[str] = ..., - languages: Optional[list[str]] = ..., - model: Union[str, VoiceAgentInputTranscriptionModel], - phrase_list: Optional[list[str]] = ..., - profanity_filter: Optional[Union[str, VoiceAgentProfanityFilterMode]] = ..., - prompt: Optional[str] = ... + created_at: datetime, + id: str, + output: Optional[str] = ..., + response_id: Optional[str] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentInputTranscriptionModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AZURE_SPEECH = "azure-speech" - AZURE_SPEECH_STREAMING = "azure-speech-streaming" - GPT4_O_MINI_TRANSCRIBE = "gpt-4o-mini-transcribe" - GPT4_O_TRANSCRIBE = "gpt-4o-transcribe" - GPT4_O_TRANSCRIBE_DIARIZE = "gpt-4o-transcribe-diarize" - GPT_LIVE_TRANSCRIBE = "gpt-live-transcribe" - GPT_REALTIME_WHISPER = "gpt-realtime-whisper" - GPT_TRANSCRIBE = "gpt-transcribe" - MAI_TRANSCRIBE = "mai-transcribe" - WHISPER1 = "whisper-1" - - - class azure.ai.projects.models.VoiceAgentInterimResponseConfig(_Model): - latency_threshold_ms: Optional[timedelta] - triggers: Optional[list[Union[str, VoiceAgentInterimResponseTrigger]]] - type: str + class azure.ai.projects.models.VoiceAgentLiveSessionResource(_Model): + audio: Optional[LiveInitialSessionAudioParam] + client: Optional[LiveClientConfigParam] + delegation: Optional[VoiceAgentLiveDelegation] + expires_at: int + id: str + input: Optional[list[LiveInitialItem]] + instructions: Optional[str] + model: Union[str, ModelIdsLive] + status: Literal["active"] + store: Optional[bool] + triggers: Optional[list[LiveDecisionTriggerInputParam]] @overload def __init__( self, *, - latency_threshold_ms: Optional[timedelta] = ..., - triggers: Optional[list[Union[str, VoiceAgentInterimResponseTrigger]]] = ..., - type: str + audio: Optional[LiveInitialSessionAudioParam] = ..., + client: Optional[LiveClientConfigParam] = ..., + delegation: Optional[VoiceAgentLiveDelegation] = ..., + expires_at: int, + id: str, + input: Optional[list[LiveInitialItem]] = ..., + instructions: Optional[str] = ..., + model: Union[str, ModelIdsLive], + store: Optional[bool] = ..., + triggers: Optional[list[LiveDecisionTriggerInputParam]] = ... ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentInterimResponseTrigger(str, Enum, metaclass=CaseInsensitiveEnumMeta): - LATENCY = "latency" - TOOL = "tool" - - class azure.ai.projects.models.VoiceAgentLlmGeneratedGreetingConfig(VoiceAgentGreetingConfig, discriminator='llm_generated'): prompt: str tool_choice: Optional[VoiceAgentToolChoice] - type: Literal["llm_generated"] + type: Literal[VoiceAgentGreetingMode.LLM_GENERATED] @overload def __init__( @@ -15948,7 +20187,7 @@ namespace azure.ai.projects.models max_completion_tokens: Optional[int] model: Optional[str] triggers: Union[list[str, VoiceAgentInterimResponseTrigger]] - type: Literal["llm_interim_response"] + type: Literal[VoiceAgentInterimResponseType.LLM_INTERIM_RESPONSE] @overload def __init__( @@ -15978,7 +20217,7 @@ namespace azure.ai.projects.models server_label: str server_url: Optional[str] tool_configs: Optional[dict[str, ToolConfig]] - type: Literal["mcp"] + type: Literal[VoiceAgentToolType.MCP] @overload def __init__( @@ -16024,6 +20263,45 @@ namespace azure.ai.projects.models NEAR_FIELD = "near_field" + class azure.ai.projects.models.VoiceAgentPostCallConfig(_Model): + destinations: list[VoiceAgentPostCallDestination] + include: Optional[list[Union[str, VoiceAgentPostCallIncludeOption]]] + + @overload + def __init__( + self, + *, + destinations: list[VoiceAgentPostCallDestination], + include: Optional[list[Union[str, VoiceAgentPostCallIncludeOption]]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentPostCallDestination(_Model): + type: str + + @overload + def __init__( + self, + *, + type: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentPostCallDestinationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + EVENT_GRID = "event_grid" + ROUTINE = "routine" + + + class azure.ai.projects.models.VoiceAgentPostCallIncludeOption(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AUDIO = "audio" + + class azure.ai.projects.models.VoiceAgentProfanityFilterMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): MASKED = "masked" REMOVED = "removed" @@ -16067,7 +20345,7 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceAgentResponseCreateParams(_Model): audio: Optional[PickPropertiesVoiceAgentAudioConfig] conversation: Optional[Union[Literal["auto"], Literal["none"], str]] - input: Optional[list[RealtimeConversationItem]] + input: Optional[list[RealtimeResponseInputItem]] instructions: Optional[str] interim_response: Optional[VoiceAgentInterimResponseConfig] max_output_tokens: Optional[Union[int, Literal["inf"]]] @@ -16085,7 +20363,7 @@ namespace azure.ai.projects.models *, audio: Optional[PickPropertiesVoiceAgentAudioConfig] = ..., conversation: Optional[Union[Literal[auto], Literal[none], str]] = ..., - input: Optional[list[RealtimeConversationItem]] = ..., + input: Optional[list[RealtimeResponseInputItem]] = ..., instructions: Optional[str] = ..., interim_response: Optional[VoiceAgentInterimResponseConfig] = ..., max_output_tokens: Optional[Union[int, Literal[inf]]] = ..., @@ -16102,10 +20380,25 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentRoutinePostCallDestination(VoiceAgentPostCallDestination, discriminator='routine'): + name: str + type: Literal[VoiceAgentPostCallDestinationType.ROUTINE] + + @overload + def __init__( + self, + *, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.VoiceAgentRtcCallErrorDetails(_Model): code: Optional[str] message: str - type: str + type: Union[str, VoiceAgentRtcCallErrorType] @overload def __init__( @@ -16113,13 +20406,18 @@ namespace azure.ai.projects.models *, code: Optional[str] = ..., message: str, - type: str + type: Union[str, VoiceAgentRtcCallErrorType] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentRtcCallErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + INVALID_REQUEST_ERROR = "invalid_request_error" + SERVER_ERROR = "server_error" + + class azure.ai.projects.models.VoiceAgentSemanticVadTurnDetection(VoiceAgentTurnDetectionConfig, discriminator='semantic_vad'): auto_truncate: bool create_response: Optional[bool] @@ -16141,6 +20439,71 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentSendDtmfSystemTool(VoiceAgentSystemTool, discriminator='send_dtmf'): + description: str + name: Literal[VoiceAgentSystemToolName.SEND_DTMF] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentSendSmsSystemTool(VoiceAgentSystemTool, discriminator='send_sms'): + description: str + name: Literal[VoiceAgentSystemToolName.SEND_SMS] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + timeout_seconds: Optional[timedelta] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentServerEventInputCollectionStatus(RealtimeServerEvent, discriminator='input_collection.status'): + call_id: str + channel: Optional[Union[str, VoiceAgentInputCollectionChannel]] + collection_id: Optional[str] + event_id: Optional[str] + output_ref: Optional[str] + request_id: Optional[str] + status: Union[str, VoiceAgentInputCollectionStatus] + type: Literal[VoiceAgentServerEventTypeExtension.INPUT_COLLECTION_STATUS] + value: Optional[str] + + @overload + def __init__( + self, + *, + call_id: str, + channel: Optional[Union[str, VoiceAgentInputCollectionChannel]] = ..., + collection_id: Optional[str] = ..., + event_id: Optional[str] = ..., + output_ref: Optional[str] = ..., + request_id: Optional[str] = ..., + status: Union[str, VoiceAgentInputCollectionStatus], + value: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.VoiceAgentServerEventResponseAnimationBlendshapesDelta(RealtimeServerEvent, discriminator='response.animation_blendshapes.delta'): content_index: int event_id: str @@ -16149,7 +20512,7 @@ namespace azure.ai.projects.models item_id: str output_index: int response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_BLENDSHAPES_DELTA] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_BLENDSHAPES_DELTA] @overload def __init__( @@ -16173,7 +20536,7 @@ namespace azure.ai.projects.models item_id: str output_index: int response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_BLENDSHAPES_DONE] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_BLENDSHAPES_DONE] @overload def __init__( @@ -16196,7 +20559,7 @@ namespace azure.ai.projects.models item_id: str output_index: int response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_VISEME_DELTA] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_VISEME_DELTA] viseme_id: int @overload @@ -16222,7 +20585,7 @@ namespace azure.ai.projects.models item_id: str output_index: int response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_VISEME_DONE] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_VISEME_DONE] @overload def __init__( @@ -16248,8 +20611,8 @@ namespace azure.ai.projects.models output_index: int response_id: str text: str - timestamp_type: Literal["word"] - type: Literal[RealtimeServerEventType.RESPONSE_AUDIO_TIMESTAMP_DELTA] + timestamp_type: Literal[VoiceAgentAudioTimestampType.WORD] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_AUDIO_TIMESTAMP_DELTA] @overload def __init__( @@ -16262,7 +20625,8 @@ namespace azure.ai.projects.models item_id: str, output_index: int, response_id: str, - text: str + text: str, + timestamp_type: Literal[VoiceAgentAudioTimestampType.WORD] ) -> None: ... @overload @@ -16275,7 +20639,7 @@ namespace azure.ai.projects.models item_id: str output_index: int response_id: str - type: Literal[RealtimeServerEventType.RESPONSE_AUDIO_TIMESTAMP_DONE] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_AUDIO_TIMESTAMP_DONE] @overload def __init__( @@ -16297,7 +20661,7 @@ namespace azure.ai.projects.models delta: str event_id: str output_index: int - type: Literal[RealtimeServerEventType.RESPONSE_VIDEO_DELTA] + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_VIDEO_DELTA] @overload def __init__( @@ -16318,7 +20682,7 @@ namespace azure.ai.projects.models event_id: Optional[str] operation: Optional[str] rtc_call_id: Optional[str] - type: Literal[RealtimeServerEventType.RTC_CALL_ERROR] + type: Literal[VoiceAgentServerEventTypeExtension.RTC_CALL_ERROR] @overload def __init__( @@ -16338,7 +20702,7 @@ namespace azure.ai.projects.models event_id: str rtc_call_id: str sdp_answer: str - type: Literal[RealtimeServerEventType.RTC_CALL_SDP_CREATED] + type: Literal[VoiceAgentServerEventTypeExtension.RTC_CALL_SDP_CREATED] @overload def __init__( @@ -16356,7 +20720,7 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceAgentServerEventSessionAvatarConnecting(RealtimeServerEvent, discriminator='session.avatar.connecting'): event_id: str server_sdp: str - type: Literal[RealtimeServerEventType.SESSION_AVATAR_CONNECTING] + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_AVATAR_CONNECTING] @overload def __init__( @@ -16373,7 +20737,7 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceAgentServerEventSessionAvatarSwitchToIdle(RealtimeServerEvent, discriminator='session.avatar.switch_to_idle'): event_id: str turn_id: Optional[str] - type: Literal[RealtimeServerEventType.SESSION_AVATAR_SWITCH_TO_IDLE] + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_AVATAR_SWITCH_TO_IDLE] @overload def __init__( @@ -16390,7 +20754,7 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceAgentServerEventSessionAvatarSwitchToSpeaking(RealtimeServerEvent, discriminator='session.avatar.switch_to_speaking'): event_id: str turn_id: Optional[str] - type: Literal[RealtimeServerEventType.SESSION_AVATAR_SWITCH_TO_SPEAKING] + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_AVATAR_SWITCH_TO_SPEAKING] @overload def __init__( @@ -16404,13 +20768,114 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentServerEventSessionHandoffAborted(RealtimeServerEvent, discriminator='session.handoff.aborted'): + edge_id: str + error: Optional[RealtimeServerEventErrorError] + event_id: str + from_model: str + from_node_id: str + handoff_id: str + node_generation: int + reason: Union[str, VoiceAgentHandoffAbortReason] + to_model: str + to_node_id: str + tool_call_id: str + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_ABORTED] + + @overload + def __init__( + self, + *, + edge_id: str, + error: Optional[RealtimeServerEventErrorError] = ..., + event_id: str, + from_model: str, + from_node_id: str, + handoff_id: str, + node_generation: int, + reason: Union[str, VoiceAgentHandoffAbortReason], + to_model: str, + to_node_id: str, + tool_call_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentServerEventSessionHandoffCompleted(RealtimeServerEvent, discriminator='session.handoff.completed'): + duration_ms: timedelta + edge_id: str + event_id: str + from_model: str + from_node_id: str + handoff_id: str + node_generation: int + prepare_duration_ms: timedelta + to_model: str + to_node_id: str + tool_call_id: str + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_COMPLETED] + + @overload + def __init__( + self, + *, + duration_ms: timedelta, + edge_id: str, + event_id: str, + from_model: str, + from_node_id: str, + handoff_id: str, + node_generation: int, + prepare_duration_ms: timedelta, + to_model: str, + to_node_id: str, + tool_call_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentServerEventSessionHandoffStarted(RealtimeServerEvent, discriminator='session.handoff.started'): + edge_id: str + event_id: str + from_model: str + from_node_id: str + handoff_id: str + node_generation: int + to_model: str + to_node_id: str + tool_call_id: str + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_STARTED] + + @overload + def __init__( + self, + *, + edge_id: str, + event_id: str, + from_model: str, + from_node_id: str, + handoff_id: str, + node_generation: int, + to_model: str, + to_node_id: str, + tool_call_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.VoiceAgentServerEventSessionSubagentAborted(RealtimeServerEvent, discriminator='session.subagent.aborted'): call_id: str consultation_id: str event_id: str reason: Union[str, VoiceAgentSubagentAbortReason] subagent_name: str - type: Literal[RealtimeServerEventType.SESSION_SUBAGENT_ABORTED] + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_ABORTED] @overload def __init__( @@ -16432,7 +20897,7 @@ namespace azure.ai.projects.models consultation_id: str event_id: str subagent_name: str - type: Literal[RealtimeServerEventType.SESSION_SUBAGENT_COMPLETED] + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_COMPLETED] @overload def __init__( @@ -16453,7 +20918,7 @@ namespace azure.ai.projects.models consultation_id: str event_id: str subagent_name: str - type: Literal[RealtimeServerEventType.SESSION_SUBAGENT_STARTED] + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_STARTED] @overload def __init__( @@ -16469,9 +20934,88 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentServerEventSystemToolArgumentsDelta(RealtimeServerEvent, discriminator='response.system_tool_arguments.delta'): + call_id: str + delta: str + event_id: str + item_id: str + obfuscation: Optional[str] + output_index: int + response_id: str + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA] + + @overload + def __init__( + self, + *, + call_id: str, + delta: str, + event_id: str, + item_id: str, + obfuscation: Optional[str] = ..., + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentServerEventSystemToolArgumentsDone(RealtimeServerEvent, discriminator='response.system_tool_arguments.done'): + arguments: str + call_id: str + event_id: str + item_id: str + name: Union[str, VoiceAgentSystemToolName] + output_index: int + response_id: str + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE] + + @overload + def __init__( + self, + *, + arguments: str, + call_id: str, + event_id: str, + item_id: str, + name: Union[str, VoiceAgentSystemToolName], + output_index: int, + response_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentServerEventTypeExtension(str, Enum, metaclass=CaseInsensitiveEnumMeta): + INPUT_COLLECTION_STATUS = "input_collection.status" + RESPONSE_ANIMATION_BLENDSHAPES_DELTA = "response.animation_blendshapes.delta" + RESPONSE_ANIMATION_BLENDSHAPES_DONE = "response.animation_blendshapes.done" + RESPONSE_ANIMATION_VISEME_DELTA = "response.animation_viseme.delta" + RESPONSE_ANIMATION_VISEME_DONE = "response.animation_viseme.done" + RESPONSE_AUDIO_TIMESTAMP_DELTA = "response.audio_timestamp.delta" + RESPONSE_AUDIO_TIMESTAMP_DONE = "response.audio_timestamp.done" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA = "response.system_tool_arguments.delta" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE = "response.system_tool_arguments.done" + RESPONSE_VIDEO_DELTA = "response.video.delta" + RTC_CALL_ERROR = "rtc.call.error" + RTC_CALL_SDP_CREATED = "rtc.call.sdp.created" + SESSION_AVATAR_CONNECTING = "session.avatar.connecting" + SESSION_AVATAR_SWITCH_TO_IDLE = "session.avatar.switch_to_idle" + SESSION_AVATAR_SWITCH_TO_SPEAKING = "session.avatar.switch_to_speaking" + SESSION_HANDOFF_ABORTED = "session.handoff.aborted" + SESSION_HANDOFF_COMPLETED = "session.handoff.completed" + SESSION_HANDOFF_STARTED = "session.handoff.started" + SESSION_SUBAGENT_ABORTED = "session.subagent.aborted" + SESSION_SUBAGENT_COMPLETED = "session.subagent.completed" + SESSION_SUBAGENT_STARTED = "session.subagent.started" + WARNING = "warning" + + class azure.ai.projects.models.VoiceAgentServerEventWarning(RealtimeServerEvent, discriminator='warning'): event_id: str - type: Literal[RealtimeServerEventType.WARNING] + type: Literal[VoiceAgentServerEventTypeExtension.WARNING] warning: VoiceAgentServerEventWarningDetails @overload @@ -16579,6 +21123,7 @@ namespace azure.ai.projects.models avatar: Optional[VoiceAgentSessionAvatarConfig] expires_at: Optional[datetime] greeting: Optional[VoiceAgentGreetingConfig] + handoff: Optional[VoiceAgentHandoffState] id: str include: Optional[list[Union[str, VoiceAgentSessionIncludeOption]]] instructions: Optional[str] @@ -16604,6 +21149,7 @@ namespace azure.ai.projects.models avatar: Optional[VoiceAgentSessionAvatarConfig] = ..., expires_at: Optional[datetime] = ..., greeting: Optional[VoiceAgentGreetingConfig] = ..., + handoff: Optional[VoiceAgentHandoffState] = ..., id: str, include: Optional[list[Union[str, VoiceAgentSessionIncludeOption]]] = ..., instructions: Optional[str] = ..., @@ -16751,7 +21297,7 @@ namespace azure.ai.projects.models latency_threshold_ms: timedelta texts: Optional[list[str]] triggers: Union[list[str, VoiceAgentInterimResponseTrigger]] - type: Literal["static_interim_response"] + type: Literal[VoiceAgentInterimResponseType.STATIC_INTERIM_RESPONSE] @overload def __init__( @@ -16766,6 +21312,11 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentSubProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LIVE = "live" + REALTIME = "realtime" + + class azure.ai.projects.models.VoiceAgentSubagent(_Model): agent_capabilities: str agent_name: str @@ -16798,13 +21349,13 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceAgentSubagentConfig(_Model): - subagents: list[VoiceAgentSubagent] + subagent_type: str @overload def __init__( self, *, - subagents: list[VoiceAgentSubagent] + subagent_type: str ) -> None: ... @overload @@ -16837,30 +21388,77 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentSubagentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + DELEGATE = "delegate" + INLINE = "inline" + + class azure.ai.projects.models.VoiceAgentSystemTool(VoiceAgentTool, discriminator='system'): description: Optional[str] name: str - type: Literal["system"] + timeout_seconds: Optional[timedelta] + type: Literal[VoiceAgentToolType.SYSTEM] @overload def __init__( self, *, description: Optional[str] = ..., - name: str + name: str, + timeout_seconds: Optional[timedelta] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentSystemToolItem(RealtimeConversationItem, discriminator='system_tool'): + arguments: str + call_id: str + created_at: Optional[datetime] + id: Optional[str] + name: Union[str, VoiceAgentSystemToolName] + object: Optional[Literal["item"]] + response_id: Optional[str] + status: Union[str, VoiceAgentSystemToolItemStatus] + type: Literal[VoiceAgentConversationItemTypeExtension.SYSTEM_TOOL] + + @overload + def __init__( + self, + *, + arguments: str, + call_id: str, + id: Optional[str] = ..., + name: Union[str, VoiceAgentSystemToolName], + object: Optional[Literal[item]] = ..., + status: Union[str, VoiceAgentSystemToolItemStatus] ) -> None: ... @overload def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentSystemToolItemStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COMPLETED = "completed" + INCOMPLETE = "incomplete" + IN_PROGRESS = "in_progress" + + class azure.ai.projects.models.VoiceAgentSystemToolName(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COLLECT_DTMF = "collect_dtmf" + COLLECT_SMS = "collect_sms" + DIGIT_RECOGNITION = "digit_recognition" END_CONVERSATION = "end_conversation" + LANGUAGE_DETECTION = "language_detection" + SEND_DTMF = "send_dtmf" + SEND_SMS = "send_sms" + TRANSFER = "transfer" class azure.ai.projects.models.VoiceAgentTemplateGreetingConfig(VoiceAgentGreetingConfig, discriminator='template'): text: str - type: Literal["template"] + type: Literal[VoiceAgentGreetingMode.TEMPLATE] @overload def __init__( @@ -16894,11 +21492,18 @@ namespace azure.ai.projects.models WHEN_IDLE = "when_idle" + class azure.ai.projects.models.VoiceAgentToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FUNCTION = "function" + MCP = "mcp" + SYSTEM = "system" + TOOLBOX = "toolbox" + + class azure.ai.projects.models.VoiceAgentToolboxTool(VoiceAgentTool, discriminator='toolbox'): response_scheduling: Optional[Union[str, VoiceAgentToolResponseScheduling]] toolbox_name: str toolbox_version: str - type: Literal["toolbox"] + type: Literal[VoiceAgentToolType.TOOLBOX] @overload def __init__( @@ -16955,6 +21560,92 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceAgentTransferDestination(_Model): + type: Union[str, VoiceAgentTransferDestinationType] + value: str + + @overload + def __init__( + self, + *, + type: Union[str, VoiceAgentTransferDestinationType], + value: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentTransferDestinationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + PHONE_NUMBER = "phone_number" + SIP = "sip" + TEAMS = "teams" + + + class azure.ai.projects.models.VoiceAgentTransferRouting(_Model): + ring_timeout_seconds: Optional[timedelta] + strategy: Union[str, VoiceAgentTransferStrategy] + + @overload + def __init__( + self, + *, + ring_timeout_seconds: Optional[timedelta] = ..., + strategy: Union[str, VoiceAgentTransferStrategy] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentTransferStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): + PARALLEL = "parallel" + RANDOM = "random" + SEQUENTIAL = "sequential" + + + class azure.ai.projects.models.VoiceAgentTransferSystemTool(VoiceAgentSystemTool, discriminator='transfer'): + description: str + name: Literal[VoiceAgentSystemToolName.TRANSFER] + require_handoff: Optional[bool] + targets: list[VoiceAgentTransferTarget] + timeout_seconds: timedelta + type: Union[str, azure.ai.projects.models.SYSTEM] + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + require_handoff: Optional[bool] = ..., + targets: list[VoiceAgentTransferTarget], + timeout_seconds: Optional[timedelta] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.ai.projects.models.VoiceAgentTransferTarget(_Model): + description: Optional[str] + destinations: list[VoiceAgentTransferDestination] + name: str + routing: VoiceAgentTransferRouting + + @overload + def __init__( + self, + *, + description: Optional[str] = ..., + destinations: list[VoiceAgentTransferDestination], + name: str, + routing: VoiceAgentTransferRouting + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.VoiceAgentTransport(str, Enum, metaclass=CaseInsensitiveEnumMeta): WEBRTC = "webrtc" WEBSOCKET = "websocket" @@ -16976,14 +21667,52 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... - class azure.ai.projects.models.VoiceAgentTurnDetectionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - AZURE_SEMANTIC_VAD = "azure_semantic_vad" - AZURE_SEMANTIC_VAD_EN = "azure_semantic_vad_en" - AZURE_SEMANTIC_VAD_MULTILINGUAL = "azure_semantic_vad_multilingual" - SEMANTIC_VAD = "semantic_vad" - SERVER_VAD = "server_vad" - - + class azure.ai.projects.models.VoiceAgentTurnDetectionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + AZURE_SEMANTIC_VAD = "azure_semantic_vad" + AZURE_SEMANTIC_VAD_EN = "azure_semantic_vad_en" + AZURE_SEMANTIC_VAD_MULTILINGUAL = "azure_semantic_vad_multilingual" + SEMANTIC_VAD = "semantic_vad" + SERVER_VAD = "server_vad" + + + class azure.ai.projects.models.VoiceAgentVoiceConfig(_Model): + custom_lexicon_url: Optional[str] + custom_text_normalization_url: Optional[str] + custom_voice_endpoint_id: Optional[str] + personal_voice_model: Optional[str] + pitch: Optional[str] + prefer_locales: Optional[list[str]] + speed: Optional[float] + style: Optional[str] + voice: Optional[str] + voice_locale: Optional[str] + voice_temperature: Optional[float] + voice_type: Optional[Union[str, VoiceType]] + volume: Optional[str] + + @overload + def __init__( + self, + *, + custom_lexicon_url: Optional[str] = ..., + custom_text_normalization_url: Optional[str] = ..., + custom_voice_endpoint_id: Optional[str] = ..., + personal_voice_model: Optional[str] = ..., + pitch: Optional[str] = ..., + prefer_locales: Optional[list[str]] = ..., + speed: Optional[float] = ..., + style: Optional[str] = ..., + voice: Optional[str] = ..., + voice_locale: Optional[str] = ..., + voice_temperature: Optional[float] = ..., + voice_type: Optional[Union[str, VoiceType]] = ..., + volume: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + class azure.ai.projects.models.VoiceAudioCodec(str, Enum, metaclass=CaseInsensitiveEnumMeta): PCM16 = "pcm16" PCMA = "pcma" @@ -17072,6 +21801,10 @@ namespace azure.ai.projects.models def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceConversationEngineType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HOSTED_AGENT = "hosted_agent" + + class azure.ai.projects.models.VoiceConversationStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): COMPLETED = "completed" FAILED = "failed" @@ -17112,7 +21845,7 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceHostedAgentConversationEngine(VoiceConversationEngine, discriminator='hosted_agent'): name: str - type: Literal["hosted_agent"] + type: Literal[VoiceConversationEngineType.HOSTED_AGENT] version: Optional[str] @overload @@ -17166,15 +21899,20 @@ namespace azure.ai.projects.models class azure.ai.projects.models.VoiceRecordingChannelLayout(_Model): - left: Literal["user"] - right: Literal["agent"] + left: Literal[VoiceAudioRole.USER] + right: Literal[VoiceAudioRole.AGENT] + @overload def __init__( self, - *args: Any, - **kwargs: Any + *, + left: Literal[VoiceAudioRole.USER], + right: Literal[VoiceAudioRole.AGENT] ) -> None: ... + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + class azure.ai.projects.models.VoiceResponse(_Model): audio: Optional[VoiceResponseAudio] @@ -18434,6 +23172,68 @@ namespace azure.ai.projects.operations ) -> ItemPaged[Insight]: ... + class azure.ai.projects.operations.BetaLive: + + def __init__( + self, + *args: Any, + **kwargs: Any + ) -> None: ... + + def connect( + self, + *, + agent_name: str, + agent_version: Optional[str] = ..., + api_version: Optional[str] = ..., + connection_url: Optional[str] = ..., + credential_scopes: Optional[list[str]] = ..., + extra_headers: Optional[Mapping[str, str]] = ..., + extra_query: Optional[Mapping[str, str]] = ..., + store: Optional[bool] = ..., + structured_inputs: Optional[Mapping[str, Any]] = ..., + **kwargs: Any + ) -> BetaLiveConnectionManager: ... + + + class azure.ai.projects.operations.BetaLiveConnection(_BaseWebSocketConnection[LiveServerEvent, LiveClientEvent]): implements ContextManager + property closed: bool # Read-only + + def __init__(self, connection: ClientConnection) -> None: ... + + def __iter__(self) -> Iterator[LiveServerEvent]: ... + + def __repr__(self) -> str: ... + + def close( + self, + *, + code: int = 1000, + reason: str = "" + ) -> None: ... + + def recv( + self, + *, + timeout: Optional[float] = ... + ) -> LiveServerEvent: ... + + def send(self, event: LiveClientEvent) -> None: ... + + + class azure.ai.projects.operations.BetaLiveConnectionManager(_BaseWebSocketConnectionManager[BetaLiveConnection]): implements ContextManager + + def __init__( + self, + *, + agent_version: Optional[str] = ..., + store: Optional[bool] = ..., + **kwargs: Any + ) -> None: ... + + def enter(self) -> BetaLiveConnection: ... + + class azure.ai.projects.operations.BetaMemoryStoresOperations(GenerateBetaMemoryStoresOperations): def __init__( @@ -18994,7 +23794,7 @@ namespace azure.ai.projects.operations ) -> BetaRealtimeConnectionManager: ... - class azure.ai.projects.operations.BetaRealtimeConnection: implements ContextManager + class azure.ai.projects.operations.BetaRealtimeConnection(_BaseWebSocketConnection[ServerEvent, ClientEvent]): implements ContextManager property closed: bool # Read-only def __init__(self, connection: ClientConnection) -> None: ... @@ -19019,7 +23819,7 @@ namespace azure.ai.projects.operations def send(self, event: ClientEvent) -> None: ... - class azure.ai.projects.operations.BetaRealtimeConnectionManager: implements ContextManager + class azure.ai.projects.operations.BetaRealtimeConnectionManager(_BaseWebSocketConnectionManager[BetaRealtimeConnection]): implements ContextManager def __init__( self, @@ -19442,6 +24242,122 @@ namespace azure.ai.projects.operations ) -> SkillDetails: ... + class azure.ai.projects.operations.BetaVoiceAgentsCampaignsOperations(GeneratedBetaVoiceAgentsCampaignsOperations): + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + def begin_cancel( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[TelephonyCampaign]: ... + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: TelephonyCampaign, + *, + content_type: str = "application/json", + etag: Optional[str] = ..., + match_condition: Optional[MatchConditions] = ..., + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[TelephonyCampaign]: ... + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: JSON, + *, + content_type: str = "application/json", + etag: Optional[str] = ..., + match_condition: Optional[MatchConditions] = ..., + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[TelephonyCampaign]: ... + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: IO[bytes], + *, + content_type: str = "application/json", + etag: Optional[str] = ..., + match_condition: Optional[MatchConditions] = ..., + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[TelephonyCampaign]: ... + + def begin_delete( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[None]: ... + + @distributed_trace + def get( + self, + agent_name: str, + campaign_name: str, + *, + operation_id: Optional[str] = ..., + **kwargs: Any + ) -> TelephonyCampaign: ... + + @distributed_trace + def get_operation( + self, + agent_name: str, + campaign_name: str, + operation_id: str, + **kwargs: Any + ) -> TelephonyCampaignOperation: ... + + @distributed_trace + def list( + self, + agent_name: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + status: Optional[Union[str, TelephonyCampaignStatus]] = ..., + **kwargs: Any + ) -> ItemPaged[TelephonyCampaign]: ... + + @distributed_trace + def list_validation_errors( + self, + agent_name: str, + campaign_name: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + **kwargs: Any + ) -> ItemPaged[TelephonyCampaignValidationError]: ... + + class azure.ai.projects.operations.BetaVoiceAgentsConversationsOperations: def __init__( @@ -19585,8 +24501,102 @@ namespace azure.ai.projects.operations ) -> ItemPaged[VoiceResponse]: ... + class azure.ai.projects.operations.BetaVoiceAgentsLiveConversationsOperations: + + def __init__( + self, + *args, + **kwargs + ) -> None: ... + + @distributed_trace + def delete( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace + def download_audio( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> Iterator[bytes]: ... + + @distributed_trace + def download_audio_item( + self, + agent_name: str, + conversation_id: str, + item_id: str, + **kwargs: Any + ) -> Iterator[bytes]: ... + + @distributed_trace + def get( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> VoiceAgentLiveConversation: ... + + @distributed_trace + def get_audio( + self, + agent_name: str, + conversation_id: str, + **kwargs: Any + ) -> VoiceRecording: ... + + @distributed_trace + def get_audio_item( + self, + agent_name: str, + conversation_id: str, + item_id: str, + **kwargs: Any + ) -> VoiceAudioItem: ... + + @distributed_trace + def get_item( + self, + agent_name: str, + conversation_id: str, + item_id: str, + **kwargs: Any + ) -> VoiceAgentLiveConversationItem: ... + + @distributed_trace + def list( + self, + agent_name: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + **kwargs: Any + ) -> ItemPaged[VoiceAgentLiveConversation]: ... + + @distributed_trace + def list_items( + self, + agent_name: str, + conversation_id: str, + *, + before: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + **kwargs: Any + ) -> ItemPaged[VoiceAgentLiveConversationItem]: ... + + class azure.ai.projects.operations.BetaVoiceAgentsOperations(GeneratedBetaVoiceAgentsOperations): + campaigns: BetaVoiceAgentsCampaignsOperations conversations: BetaVoiceAgentsConversationsOperations + live: BetaLive + live_conversations: BetaVoiceAgentsLiveConversationsOperations realtime: BetaRealtime telephony: BetaVoiceAgentsTelephonyOperations @@ -19620,7 +24630,7 @@ namespace azure.ai.projects.operations def create_binding( self, agent_name: str, - telephony_binding: CreateTelephonyBindingRequest, + binding: TelephonyBinding, *, content_type: str = "application/json", **kwargs: Any @@ -19630,7 +24640,7 @@ namespace azure.ai.projects.operations def create_binding( self, agent_name: str, - telephony_binding: JSON, + binding: JSON, *, content_type: str = "application/json", **kwargs: Any @@ -19640,7 +24650,7 @@ namespace azure.ai.projects.operations def create_binding( self, agent_name: str, - telephony_binding: IO[bytes], + binding: IO[bytes], *, content_type: str = "application/json", **kwargs: Any @@ -19650,7 +24660,7 @@ namespace azure.ai.projects.operations def create_call_job( self, agent_name: str, - body: CreateTelephonyCallJobRequest, + job: TelephonyCallJobCreate, *, content_type: str = "application/json", idempotency_key: str, @@ -19661,7 +24671,7 @@ namespace azure.ai.projects.operations def create_call_job( self, agent_name: str, - body: JSON, + job: JSON, *, content_type: str = "application/json", idempotency_key: str, @@ -19672,7 +24682,7 @@ namespace azure.ai.projects.operations def create_call_job( self, agent_name: str, - body: IO[bytes], + job: IO[bytes], *, content_type: str = "application/json", idempotency_key: str, @@ -19690,6 +24700,14 @@ namespace azure.ai.projects.operations **kwargs: Any ) -> None: ... + @distributed_trace + def delete_call_job( + self, + agent_name: str, + call_job_id: str, + **kwargs: Any + ) -> None: ... + @distributed_trace def end_call( self, @@ -19738,10 +24756,22 @@ namespace azure.ai.projects.operations limit: Optional[int] = ..., order: Optional[Union[str, PageOrder]] = ..., provider: Optional[Union[str, TelephonyProvider]] = ..., - status: Optional[Union[str, TelephonyBindingStatus]] = ..., **kwargs: Any ) -> ItemPaged[TelephonyBindingListItem]: ... + @distributed_trace + def list_call_jobs( + self, + agent_name: str, + *, + before: Optional[str] = ..., + campaign_name: Optional[str] = ..., + limit: Optional[int] = ..., + order: Optional[Union[str, PageOrder]] = ..., + status: Optional[Union[str, TelephonyCallJobStatus]] = ..., + **kwargs: Any + ) -> ItemPaged[TelephonyCallJob]: ... + @distributed_trace def list_calls( self, diff --git a/sdk/ai/azure-ai-projects/api.metadata.yml b/sdk/ai/azure-ai-projects/api.metadata.yml index cd854aee232c..8368e9dbfddf 100644 --- a/sdk/ai/azure-ai-projects/api.metadata.yml +++ b/sdk/ai/azure-ai-projects/api.metadata.yml @@ -1,4 +1,4 @@ -apiHash: 4d010ad6620cc1bb8549f8521d271bd7641a19b194d9502ff3e233d95dd05f57 -packageVersion: 2.10.0 +apiHash: 7dadb152e4753a2fe41a0e92a5e2574a3334d5f5193f88d37381fd4977217393 +packageVersion: 2.11.0 parserVersion: 0.3.31 pythonVersion: 3.12.4 diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index 941d9bf2c1ce..bcd5477c98c4 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -97,12 +97,19 @@ "azure.ai.projects.models.AgentTaxonomyInput": "Azure.AI.Projects.AgentTaxonomyInput", "azure.ai.projects.models.AgentVersionDetails": "Azure.AI.Projects.AgentVersionObject", "azure.ai.projects.models.AISearchIndexResource": "Azure.AI.Projects.AISearchIndexResource", + "azure.ai.projects.models.AnswerResource": "OpenAI.AnswerResource", + "azure.ai.projects.models.AnswerResourceChoice": "OpenAI.AnswerResourceChoice", + "azure.ai.projects.models.AnswerResourcePredicate": "OpenAI.AnswerResourcePredicate", + "azure.ai.projects.models.AnswerResourceRefusal": "OpenAI.AnswerResourceRefusal", + "azure.ai.projects.models.AnswerResourceScore": "OpenAI.AnswerResourceScore", "azure.ai.projects.models.ApiError": "OpenAI.Error", "azure.ai.projects.models.ApiErrorResponse": "Azure.AI.Projects.ApiErrorResponse", "azure.ai.projects.models.ApiKeyCredentials": "Azure.AI.Projects.ApiKeyCredentials", - "azure.ai.projects.models.ApplyPatchToolParam": "OpenAI.ApplyPatchToolParam", + "azure.ai.projects.models.ApplyPatchToolParam": "OpenAI.ToolApplyPatchToolParam", "azure.ai.projects.models.ApproximateLocation": "OpenAI.ApproximateLocation", "azure.ai.projects.models.ArtifactProfile": "Azure.AI.Projects.ArtifactProfile", + "azure.ai.projects.models.TelephonyCampaignSchedule": "Azure.AI.Projects.TelephonyCampaignSchedule", + "azure.ai.projects.models.AtTimeSchedule": "Azure.AI.Projects.AtTimeSchedule", "azure.ai.projects.models.AutoCodeInterpreterToolParam": "OpenAI.AutoCodeInterpreterToolParam", "azure.ai.projects.models.EvaluationTarget": "Azure.AI.Projects.FoundryEvaluationTarget", "azure.ai.projects.models.AzureAIAgentTarget": "Azure.AI.Projects.AzureAIAgentTarget", @@ -141,17 +148,18 @@ "azure.ai.projects.models.ChatCompletionTool": "OpenAI.ChatCompletionTool", "azure.ai.projects.models.MemoryItem": "Azure.AI.Projects.MemoryItem", "azure.ai.projects.models.ChatSummaryMemoryItem": "Azure.AI.Projects.ChatSummaryMemoryItem", + "azure.ai.projects.models.ChoiceProbabilityResource": "OpenAI.ChoiceProbabilityResource", "azure.ai.projects.models.ClusterInsightResult": "Azure.AI.Projects.ClusterInsightResult", "azure.ai.projects.models.ClusterTokenUsage": "Azure.AI.Projects.ClusterTokenUsage", "azure.ai.projects.models.EvaluatorDefinition": "Azure.AI.Projects.EvaluatorDefinition", "azure.ai.projects.models.CodeBasedEvaluatorDefinition": "Azure.AI.Projects.CodeBasedEvaluatorDefinition", "azure.ai.projects.models.CodeConfiguration": "Azure.AI.Projects.CodeConfiguration", - "azure.ai.projects.models.CodeInterpreterTool": "OpenAI.CodeInterpreterTool", + "azure.ai.projects.models.CodeInterpreterTool": "OpenAI.ToolCodeInterpreterTool", "azure.ai.projects.models.CodeInterpreterToolboxTool": "Azure.AI.Projects.CodeInterpreterToolboxTool", "azure.ai.projects.models.ComparisonFilter": "OpenAI.ComparisonFilter", "azure.ai.projects.models.CompoundFilter": "OpenAI.CompoundFilter", - "azure.ai.projects.models.ComputerTool": "OpenAI.ComputerTool", - "azure.ai.projects.models.ComputerUsePreviewTool": "OpenAI.ComputerUsePreviewTool", + "azure.ai.projects.models.ComputerTool": "OpenAI.ToolComputerTool", + "azure.ai.projects.models.ComputerUsePreviewTool": "OpenAI.ToolComputerUsePreviewTool", "azure.ai.projects.models.Connection": "Azure.AI.Projects.Connection", "azure.ai.projects.models.FunctionShellToolParamEnvironment": "OpenAI.FunctionShellToolParamEnvironment", "azure.ai.projects.models.ContainerAutoParam": "OpenAI.ContainerAutoParam", @@ -166,11 +174,7 @@ "azure.ai.projects.models.CosmosDBIndex": "Azure.AI.Projects.CosmosDBIndex", "azure.ai.projects.models.CreateAsyncResponse": "Azure.AI.Projects.createAsync.Response.anonymous", "azure.ai.projects.models.CreateSkillVersionFromFilesBody": "Azure.AI.Projects.CreateSkillVersionFromFilesBody", - "azure.ai.projects.models.CreateTelephonyBindingRequest": "Azure.AI.Projects.CreateTelephonyBindingRequest", - "azure.ai.projects.models.CreateTeamsPhoneExtensibilityTelephonyBindingRequest": "Azure.AI.Projects.CreateTeamsPhoneExtensibilityTelephonyBindingRequest", - "azure.ai.projects.models.CreateTelephonyCallJobRequest": "Azure.AI.Projects.CreateTelephonyCallJobRequest", "azure.ai.projects.models.CreateTranscriptionResponseJsonUsage": "OpenAI.CreateTranscriptionResponseJsonUsage", - "azure.ai.projects.models.CreateTwilioTelephonyBindingRequest": "Azure.AI.Projects.CreateTwilioTelephonyBindingRequest", "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", @@ -179,7 +183,7 @@ "azure.ai.projects.models.RoutineTrigger": "Azure.AI.Projects.RoutineTrigger", "azure.ai.projects.models.CustomRoutineTrigger": "Azure.AI.Projects.CustomRoutineTrigger", "azure.ai.projects.models.CustomTextFormatParam": "OpenAI.CustomTextFormatParam", - "azure.ai.projects.models.CustomToolParam": "OpenAI.CustomToolParam", + "azure.ai.projects.models.CustomToolParam": "OpenAI.ToolCustomToolParam", "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", @@ -192,8 +196,9 @@ "azure.ai.projects.models.DatasetCredential": "Azure.AI.Projects.AssetCredentialResponse", "azure.ai.projects.models.DatasetDataGenerationJobOutput": "Azure.AI.Projects.DatasetDataGenerationJobOutput", "azure.ai.projects.models.DatasetEvaluatorGenerationJobSource": "Azure.AI.Projects.DatasetEvaluatorGenerationJobSource", - "azure.ai.projects.models.DatasetReference": "Azure.AI.Projects.DatasetReference", + "azure.ai.projects.models.DatasetReference": "Azure.AI.Projects.VersionedDatasetReference", "azure.ai.projects.models.DatasetVersion": "Azure.AI.Projects.DatasetVersion", + "azure.ai.projects.models.DecisionResponse": "OpenAI.DecisionResponse", "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", @@ -244,18 +249,20 @@ "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.FileSearchTool": "OpenAI.ToolFileSearchTool", "azure.ai.projects.models.FileSearchToolboxTool": "Azure.AI.Projects.FileSearchToolboxTool", + "azure.ai.projects.models.TelephonyOutboundRetryPolicy": "Azure.AI.Projects.TelephonyOutboundRetryPolicy", + "azure.ai.projects.models.FixedIntervalRetryPolicy": "Azure.AI.Projects.FixedIntervalRetryPolicy", "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.FunctionObject": "OpenAI.FunctionObject", "azure.ai.projects.models.FunctionParameters": "OpenAI.FunctionParameters", - "azure.ai.projects.models.FunctionShellToolParam": "OpenAI.FunctionShellToolParam", + "azure.ai.projects.models.FunctionShellToolParam": "OpenAI.ToolFunctionShellToolParam", "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.FunctionTool": "OpenAI.ToolFunctionTool", "azure.ai.projects.models.FunctionToolParam": "OpenAI.FunctionToolParam", "azure.ai.projects.models.GenerateVoiceAgentRequest": "Azure.AI.Projects.GenerateVoiceAgentRequest", "azure.ai.projects.models.GitHubCopilotHarness": "Azure.AI.Projects.GitHubCopilotHarness", @@ -269,10 +276,13 @@ "azure.ai.projects.models.HourlyRecurrenceSchedule": "Azure.AI.Projects.HourlyRecurrenceSchedule", "azure.ai.projects.models.HumanEvaluationPreviewRuleAction": "Azure.AI.Projects.HumanEvaluationPreviewRuleAction", "azure.ai.projects.models.HybridSearchOptions": "OpenAI.HybridSearchOptions", - "azure.ai.projects.models.ImageGenTool": "OpenAI.ImageGenTool", + "azure.ai.projects.models.ImageGenTool": "OpenAI.ToolImageGenTool", "azure.ai.projects.models.ImageGenToolInputImageMask": "OpenAI.ImageGenToolInputImageMask", + "azure.ai.projects.models.ImmediateSchedule": "Azure.AI.Projects.ImmediateSchedule", "azure.ai.projects.models.InlineSkillParam": "OpenAI.InlineSkillParam", "azure.ai.projects.models.InlineSkillSourceParam": "OpenAI.InlineSkillSourceParam", + "azure.ai.projects.models.InlineVoiceSubagent": "Azure.AI.Projects.InlineVoiceSubagent", + "azure.ai.projects.models.InputTokensDetailsResource": "OpenAI.InputTokensDetailsResource", "azure.ai.projects.models.Insight": "Azure.AI.Projects.Insight", "azure.ai.projects.models.InsightCluster": "Azure.AI.Projects.InsightCluster", "azure.ai.projects.models.InsightModelConfiguration": "Azure.AI.Projects.InsightModelConfiguration", @@ -287,7 +297,148 @@ "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.LiveAllowedServerEventParam": "OpenAI.LiveAllowedServerEventParam", + "azure.ai.projects.models.LiveAllowedToolsChoiceParam": "OpenAI.LiveAllowedToolsChoiceParam", + "azure.ai.projects.models.LiveApplyPatchToolInputParam": "OpenAI.LiveApplyPatchToolInputParam", + "azure.ai.projects.models.LiveAudioFormat": "OpenAI.LiveAudioFormat", + "azure.ai.projects.models.LiveClientConfigParam": "OpenAI.LiveClientConfigParam", + "azure.ai.projects.models.LiveClientEvent": "OpenAI.LiveClientEvent", + "azure.ai.projects.models.LiveClientEventLiveCommentaryAppendParam": "OpenAI.LiveClientEventLiveCommentaryAppendParam", + "azure.ai.projects.models.LiveClientEventLiveDecisionCreateParam": "OpenAI.LiveClientEventLiveDecisionCreateParam", + "azure.ai.projects.models.LiveClientEventLiveDecisionItemCreateParam": "OpenAI.LiveClientEventLiveDecisionItemCreateParam", + "azure.ai.projects.models.LiveClientEventLiveDecisionItemDeleteParam": "OpenAI.LiveClientEventLiveDecisionItemDeleteParam", + "azure.ai.projects.models.LiveClientEventLiveInputAudioAppendEvent": "OpenAI.LiveClientEventLiveInputAudioAppendEvent", + "azure.ai.projects.models.LiveClientEventLiveInputAudioMuteParam": "OpenAI.LiveClientEventLiveInputAudioMuteParam", + "azure.ai.projects.models.LiveClientEventLiveInputAudioUnmuteParam": "OpenAI.LiveClientEventLiveInputAudioUnmuteParam", + "azure.ai.projects.models.LiveClientEventLiveInstructionsAppendParam": "OpenAI.LiveClientEventLiveInstructionsAppendParam", + "azure.ai.projects.models.LiveClientEventLiveOutputAudioFixturePlayParam": "OpenAI.LiveClientEventLiveOutputAudioFixturePlayParam", + "azure.ai.projects.models.LiveClientEventLiveResponseCreateParam": "OpenAI.LiveClientEventLiveResponseCreateParam", + "azure.ai.projects.models.LiveClientEventLiveResponseItemCreateParam": "OpenAI.LiveClientEventLiveResponseItemCreateParam", + "azure.ai.projects.models.LiveClientEventLiveSessionCloseParam": "OpenAI.LiveClientEventLiveSessionCloseParam", + "azure.ai.projects.models.LiveClientEventLiveSessionUpdateParam": "OpenAI.LiveClientEventLiveSessionUpdateParam", + "azure.ai.projects.models.LiveClientEventLiveThinkingAppendParam": "OpenAI.LiveClientEventLiveThinkingAppendParam", + "azure.ai.projects.models.LiveCodeInterpreterToolInputParam": "OpenAI.LiveCodeInterpreterToolInputParam", + "azure.ai.projects.models.LiveComputerToolInputParam": "OpenAI.LiveComputerToolInputParam", + "azure.ai.projects.models.LiveContainerNetworkPolicyDisabledParam": "OpenAI.LiveContainerNetworkPolicyDisabledParam", + "azure.ai.projects.models.LiveContainerReferenceParam": "OpenAI.LiveContainerReferenceParam", + "azure.ai.projects.models.LiveContextWindowUsage": "OpenAI.LiveContextWindowUsage", + "azure.ai.projects.models.LiveCustomToolInputParam": "OpenAI.LiveCustomToolInputParam", + "azure.ai.projects.models.LiveCustomVoiceParam": "OpenAI.LiveCustomVoiceParam", + "azure.ai.projects.models.LiveDataChannelConfigParam": "OpenAI.LiveDataChannelConfigParam", + "azure.ai.projects.models.LiveDecisionChoiceParam": "OpenAI.LiveDecisionChoiceParam", + "azure.ai.projects.models.LiveDecisionQuestion": "OpenAI.LiveDecisionQuestion", + "azure.ai.projects.models.LiveDecisionChoiceQuestionParam": "OpenAI.LiveDecisionChoiceQuestionParam", + "azure.ai.projects.models.LiveDecisionCompleted": "OpenAI.LiveDecisionCompleted", + "azure.ai.projects.models.LiveDecisionInputItemParam": "OpenAI.LiveDecisionInputItemParam", + "azure.ai.projects.models.LiveDecisionCustomToolCallOutputParam": "OpenAI.LiveDecisionCustomToolCallOutputParam", + "azure.ai.projects.models.LiveDecisionCustomToolCallParam": "OpenAI.LiveDecisionCustomToolCallParam", + "azure.ai.projects.models.LiveDecisionFunctionCallOutputParam": "OpenAI.LiveDecisionFunctionCallOutputParam", + "azure.ai.projects.models.LiveDecisionFunctionCallParam": "OpenAI.LiveDecisionFunctionCallParam", + "azure.ai.projects.models.LiveDecisionInputImageParam": "OpenAI.LiveDecisionInputImageParam", + "azure.ai.projects.models.LiveDecisionInputItemParamMessage": "OpenAI.LiveDecisionInputItemParamMessage", + "azure.ai.projects.models.LiveDecisionInputJsonParam": "OpenAI.LiveDecisionInputJsonParam", + "azure.ai.projects.models.LiveDecisionInputTextParam": "OpenAI.LiveDecisionInputTextParam", + "azure.ai.projects.models.LiveDecisionJsonObject": "OpenAI.LiveDecisionJsonObject", + "azure.ai.projects.models.LiveDecisionPredicateQuestionParam": "OpenAI.LiveDecisionPredicateQuestionParam", + "azure.ai.projects.models.LiveDecisionQuestionsInputParam": "OpenAI.LiveDecisionQuestionsInputParam", + "azure.ai.projects.models.LiveDecisionScoreLevelParam": "OpenAI.LiveDecisionScoreLevelParam", + "azure.ai.projects.models.LiveDecisionScoreQuestionParam": "OpenAI.LiveDecisionScoreQuestionParam", + "azure.ai.projects.models.LiveSessionUpdateParamsDelegation": "OpenAI.LiveSessionUpdateParamsDelegation", + "azure.ai.projects.models.LiveDecisionsDelegationUpdateParam": "OpenAI.LiveDecisionsDelegationUpdateParam", + "azure.ai.projects.models.LiveDecisionsSettingsInputParam": "OpenAI.LiveDecisionsSettingsInputParam", + "azure.ai.projects.models.LiveDecisionsSettingsUpdateParam": "OpenAI.LiveDecisionsSettingsUpdateParam", + "azure.ai.projects.models.LiveDecisionStoredInputItemParam": "OpenAI.LiveDecisionStoredInputItemParam", + "azure.ai.projects.models.LiveDecisionStoredCustomToolCallOutputParam": "OpenAI.LiveDecisionStoredCustomToolCallOutputParam", + "azure.ai.projects.models.LiveDecisionStoredCustomToolCallParam": "OpenAI.LiveDecisionStoredCustomToolCallParam", + "azure.ai.projects.models.LiveDecisionStoredFunctionCallOutputParam": "OpenAI.LiveDecisionStoredFunctionCallOutputParam", + "azure.ai.projects.models.LiveDecisionStoredFunctionCallParam": "OpenAI.LiveDecisionStoredFunctionCallParam", + "azure.ai.projects.models.LiveDecisionStoredInputItemParamMessage": "OpenAI.LiveDecisionStoredInputItemParamMessage", + "azure.ai.projects.models.LiveDecisionTriggerInputParam": "OpenAI.LiveDecisionTriggerInputParam", + "azure.ai.projects.models.LiveDelegationReasoningInputParam": "OpenAI.LiveDelegationReasoningInputParam", + "azure.ai.projects.models.LiveDelegationTextInputParam": "OpenAI.LiveDelegationTextInputParam", + "azure.ai.projects.models.LiveFileSearchToolInputParam": "OpenAI.LiveFileSearchToolInputParam", + "azure.ai.projects.models.LiveFunctionToolChoiceParam": "OpenAI.LiveFunctionToolChoiceParam", + "azure.ai.projects.models.LiveFunctionToolInputParam": "OpenAI.LiveFunctionToolInputParam", + "azure.ai.projects.models.LiveHostedShellContainerAutoParam": "OpenAI.LiveHostedShellContainerAutoParam", + "azure.ai.projects.models.LiveHostedShellNetworkPolicyAllowlistParam": "OpenAI.LiveHostedShellNetworkPolicyAllowlistParam", + "azure.ai.projects.models.LiveHostedShellToolInputParam": "OpenAI.LiveHostedShellToolInputParam", + "azure.ai.projects.models.LiveImageGenerationToolInputParam": "OpenAI.LiveImageGenerationToolInputParam", + "azure.ai.projects.models.LiveInitialItem": "OpenAI.LiveInitialItem", + "azure.ai.projects.models.LiveInitialAssistantMessageItemParam": "OpenAI.LiveInitialAssistantMessageItemParam", + "azure.ai.projects.models.LiveInitialDeveloperMessageItemParam": "OpenAI.LiveInitialDeveloperMessageItemParam", + "azure.ai.projects.models.LiveInitialInputTextContentPartParam": "OpenAI.LiveInitialInputTextContentPartParam", + "azure.ai.projects.models.LiveInitialOutputTextContentPartParam": "OpenAI.LiveInitialOutputTextContentPartParam", + "azure.ai.projects.models.LiveInitialSessionAudioOutputParam": "OpenAI.LiveInitialSessionAudioOutputParam", + "azure.ai.projects.models.LiveInitialSessionAudioParam": "OpenAI.LiveInitialSessionAudioParam", + "azure.ai.projects.models.LiveInitialTextContentPartParam": "OpenAI.LiveInitialTextContentPartParam", + "azure.ai.projects.models.LiveInitialUserMessageItemParam": "OpenAI.LiveInitialUserMessageItemParam", + "azure.ai.projects.models.LiveInlineSkillParam": "OpenAI.LiveInlineSkillParam", + "azure.ai.projects.models.LiveInlineSkillSourceParam": "OpenAI.LiveInlineSkillSourceParam", + "azure.ai.projects.models.LiveServerEvent": "OpenAI.LiveServerEvent", + "azure.ai.projects.models.LiveInputAudioAppend": "OpenAI.LiveInputAudioAppend", + "azure.ai.projects.models.LiveLiveError": "OpenAI.LiveLiveError", + "azure.ai.projects.models.LiveLocalEnvironmentParam": "OpenAI.LiveLocalEnvironmentParam", + "azure.ai.projects.models.LiveLocalSkillParam": "OpenAI.LiveLocalSkillParam", + "azure.ai.projects.models.LiveMCPToolChoiceParam": "OpenAI.LiveMCPToolChoiceParam", + "azure.ai.projects.models.LiveMCPToolInputParam": "OpenAI.LiveMCPToolInputParam", + "azure.ai.projects.models.LiveNamespaceToolInputParam": "OpenAI.LiveNamespaceToolInputParam", + "azure.ai.projects.models.LiveOutputAudioDelta": "OpenAI.LiveOutputAudioDelta", + "azure.ai.projects.models.LiveProgrammaticToolInputParam": "OpenAI.LiveProgrammaticToolInputParam", + "azure.ai.projects.models.LiveResponsesDelegationSettingsInputParam": "OpenAI.LiveResponsesDelegationSettingsInputParam", + "azure.ai.projects.models.LiveResponsesDelegationSettingsUpdateInputParam": "OpenAI.LiveResponsesDelegationSettingsUpdateInputParam", + "azure.ai.projects.models.LiveResponsesDelegationUpdateParam": "OpenAI.LiveResponsesDelegationUpdateParam", + "azure.ai.projects.models.LiveServerEventLiveCommentaryAppended": "OpenAI.LiveServerEventLiveCommentaryAppended", + "azure.ai.projects.models.LiveServerEventLiveDecisionEvent": "OpenAI.LiveServerEventLiveDecisionEvent", + "azure.ai.projects.models.LiveServerEventLiveDecisionItemCreated": "OpenAI.LiveServerEventLiveDecisionItemCreated", + "azure.ai.projects.models.LiveServerEventLiveDecisionItemDeleted": "OpenAI.LiveServerEventLiveDecisionItemDeleted", + "azure.ai.projects.models.LiveServerEventLiveDelegationCreated": "OpenAI.LiveServerEventLiveDelegationCreated", + "azure.ai.projects.models.LiveServerEventLiveErrorEvent": "OpenAI.LiveServerEventLiveErrorEvent", + "azure.ai.projects.models.LiveServerEventLiveInfoEvent": "OpenAI.LiveServerEventLiveInfoEvent", + "azure.ai.projects.models.LiveServerEventLiveInputAudioMuted": "OpenAI.LiveServerEventLiveInputAudioMuted", + "azure.ai.projects.models.LiveServerEventLiveInputAudioUnmuted": "OpenAI.LiveServerEventLiveInputAudioUnmuted", + "azure.ai.projects.models.LiveServerEventLiveInputTranscriptDelta": "OpenAI.LiveServerEventLiveInputTranscriptDelta", + "azure.ai.projects.models.LiveServerEventLiveInstructionsAppended": "OpenAI.LiveServerEventLiveInstructionsAppended", + "azure.ai.projects.models.LiveServerEventLiveOutputAudioFixturePlayed": "OpenAI.LiveServerEventLiveOutputAudioFixturePlayed", + "azure.ai.projects.models.LiveServerEventLiveOutputAudioFixturePlaying": "OpenAI.LiveServerEventLiveOutputAudioFixturePlaying", + "azure.ai.projects.models.LiveServerEventLiveOutputTranscriptDelta": "OpenAI.LiveServerEventLiveOutputTranscriptDelta", + "azure.ai.projects.models.LiveServerEventLiveResponseEvent": "OpenAI.LiveServerEventLiveResponseEvent", + "azure.ai.projects.models.LiveServerEventLiveSessionClosed": "OpenAI.LiveServerEventLiveSessionClosed", + "azure.ai.projects.models.LiveServerEventLiveSessionStarted": "OpenAI.LiveServerEventLiveSessionStarted", + "azure.ai.projects.models.LiveServerEventLiveSessionUpdated": "OpenAI.LiveServerEventLiveSessionUpdated", + "azure.ai.projects.models.LiveServerEventLiveSessionUsageUpdated": "OpenAI.LiveServerEventLiveSessionUsageUpdated", + "azure.ai.projects.models.LiveServerEventLiveThinkingAppended": "OpenAI.LiveServerEventLiveThinkingAppended", + "azure.ai.projects.models.LiveServerEventLiveTransportAnswered": "OpenAI.LiveServerEventLiveTransportAnswered", + "azure.ai.projects.models.LiveServerEventLiveTransportDtmfReceived": "OpenAI.LiveServerEventLiveTransportDtmfReceived", + "azure.ai.projects.models.LiveServerEventLiveTransportDtmfSent": "OpenAI.LiveServerEventLiveTransportDtmfSent", + "azure.ai.projects.models.LiveServerEventLiveTransportFailed": "OpenAI.LiveServerEventLiveTransportFailed", + "azure.ai.projects.models.LiveServerEventLiveTransportRinging": "OpenAI.LiveServerEventLiveTransportRinging", + "azure.ai.projects.models.LiveSessionAudioFormatPCMAParam": "OpenAI.LiveSessionAudioFormatPCMAParam", + "azure.ai.projects.models.LiveSessionAudioFormatPCMParam": "OpenAI.LiveSessionAudioFormatPCMParam", + "azure.ai.projects.models.LiveSessionAudioFormatPCMUParam": "OpenAI.LiveSessionAudioFormatPCMUParam", + "azure.ai.projects.models.LiveSessionCreateParams": "OpenAI.LiveSessionCreateParams", + "azure.ai.projects.models.LiveSessionCreateParamsDelegation": "OpenAI.LiveSessionCreateParamsDelegation", + "azure.ai.projects.models.LiveSessionCreateParamsDelegationLiveClientDelegationParam": "OpenAI.LiveSessionCreateParamsDelegationLiveClientDelegationParam", + "azure.ai.projects.models.LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam": "OpenAI.LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam", + "azure.ai.projects.models.LiveSessionCreateParamsDelegationLiveResponsesDelegationParam": "OpenAI.LiveSessionCreateParamsDelegationLiveResponsesDelegationParam", + "azure.ai.projects.models.LiveSessionStartEvent": "OpenAI.LiveSessionStartEvent", + "azure.ai.projects.models.LiveSessionUpdateParams": "OpenAI.LiveSessionUpdateParams", + "azure.ai.projects.models.LiveSessionUpdateParamsDelegationLiveClientDelegationParam": "OpenAI.LiveSessionUpdateParamsDelegationLiveClientDelegationParam", + "azure.ai.projects.models.LiveSessionUsage": "OpenAI.LiveSessionUsage", + "azure.ai.projects.models.LiveSkillReferenceParam": "OpenAI.LiveSkillReferenceParam", + "azure.ai.projects.models.LiveSpecificApplyPatchParam": "OpenAI.LiveSpecificApplyPatchParam", + "azure.ai.projects.models.LiveSpecificCodeInterpreterParam": "OpenAI.LiveSpecificCodeInterpreterParam", + "azure.ai.projects.models.LiveSpecificComputerParam": "OpenAI.LiveSpecificComputerParam", + "azure.ai.projects.models.LiveSpecificCustomToolParam": "OpenAI.LiveSpecificCustomToolParam", + "azure.ai.projects.models.LiveSpecificFileSearchParam": "OpenAI.LiveSpecificFileSearchParam", + "azure.ai.projects.models.LiveSpecificFunctionShellParam": "OpenAI.LiveSpecificFunctionShellParam", + "azure.ai.projects.models.LiveSpecificImageGenParam": "OpenAI.LiveSpecificImageGenParam", + "azure.ai.projects.models.LiveSpecificProgrammaticToolCallingParam": "OpenAI.LiveSpecificProgrammaticToolCallingParam", + "azure.ai.projects.models.LiveSpecificWebSearchParam": "OpenAI.LiveSpecificWebSearchParam", + "azure.ai.projects.models.LiveSpecificWebSearchPreviewParam": "OpenAI.LiveSpecificWebSearchPreviewParam", + "azure.ai.projects.models.LiveToolSearchToolInputParam": "OpenAI.LiveToolSearchToolInputParam", + "azure.ai.projects.models.LiveTransportCallError": "OpenAI.LiveTransportCallError", + "azure.ai.projects.models.LiveWebSearchToolInputParam": "OpenAI.LiveWebSearchToolInputParam", + "azure.ai.projects.models.LocalShellToolParam": "OpenAI.ToolLocalShellToolParam", "azure.ai.projects.models.LocalSkillParam": "OpenAI.LocalSkillParam", "azure.ai.projects.models.LogProbProperties": "OpenAI.LogProbProperties", "azure.ai.projects.models.LoraConfig": "Azure.AI.Projects.LoraConfig", @@ -297,7 +448,7 @@ "azure.ai.projects.models.MCPListToolsToolAnnotations": "OpenAI.MCPListToolsToolAnnotations", "azure.ai.projects.models.MCPListToolsToolInputSchema": "OpenAI.MCPListToolsToolInputSchema", "azure.ai.projects.models.McpProtocolConfiguration": "Azure.AI.Projects.McpProtocolConfiguration", - "azure.ai.projects.models.MCPTool": "OpenAI.MCPTool", + "azure.ai.projects.models.MCPTool": "OpenAI.ToolMcpTool", "azure.ai.projects.models.MCPToolboxTool": "Azure.AI.Projects.MCPToolboxTool", "azure.ai.projects.models.MCPToolFilter": "OpenAI.MCPToolFilter", "azure.ai.projects.models.MCPToolRequireApproval": "OpenAI.MCPToolRequireApproval", @@ -350,11 +501,15 @@ "azure.ai.projects.models.OptimizationContext": "Azure.AI.Projects.OptimizationContext", "azure.ai.projects.models.TelemetryEndpoint": "Azure.AI.Projects.TelemetryEndpoint", "azure.ai.projects.models.OtlpTelemetryEndpoint": "Azure.AI.Projects.OtlpTelemetryEndpoint", + "azure.ai.projects.models.OutputTokensDetailsResource": "OpenAI.OutputTokensDetailsResource", "azure.ai.projects.models.PendingUploadRequest": "Azure.AI.Projects.PendingUploadRequest", "azure.ai.projects.models.PendingUploadResponse": "Azure.AI.Projects.PendingUploadResponse", + "azure.ai.projects.models.PerRecipientSchedule": "Azure.AI.Projects.PerRecipientSchedule", + "azure.ai.projects.models.TelephonyAddress": "Azure.AI.Projects.TelephonyAddress", + "azure.ai.projects.models.PhoneNumber": "Azure.AI.Projects.PhoneNumber", "azure.ai.projects.models.PickPropertiesVoiceAgentAudioConfig": "TypeSpec.PickProperties", "azure.ai.projects.models.ProceduralMemoryItem": "Azure.AI.Projects.ProceduralMemoryItem", - "azure.ai.projects.models.ProgrammaticToolCallingParam": "OpenAI.ProgrammaticToolCallingParam", + "azure.ai.projects.models.ProgrammaticToolCallingParam": "OpenAI.ToolProgrammaticToolCallingParam", "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", @@ -363,8 +518,6 @@ "azure.ai.projects.models.PromptOptimizationConfiguration": "Azure.AI.Projects.PromptOptimizationConfiguration", "azure.ai.projects.models.ProtocolConfiguration": "Azure.AI.Projects.ProtocolConfiguration", "azure.ai.projects.models.ProtocolVersionRecord": "Azure.AI.Projects.ProtocolVersionRecord", - "azure.ai.projects.models.TelephonyTransferDestination": "Azure.AI.Projects.TelephonyTransferDestination", - "azure.ai.projects.models.PSTNTelephonyTransferDestination": "Azure.AI.Projects.PSTNTelephonyTransferDestination", "azure.ai.projects.models.RaiConfig": "Azure.AI.Projects.RaiConfig", "azure.ai.projects.models.RaiInvocationModeration": "Azure.AI.Projects.RaiInvocationModeration", "azure.ai.projects.models.RaiSseTextSelector": "Azure.AI.Projects.RaiSseTextSelector", @@ -405,6 +558,18 @@ "azure.ai.projects.models.RealtimeMCPToolCall": "OpenAI.RealtimeMCPToolCall", "azure.ai.projects.models.RealtimeMCPToolExecutionError": "OpenAI.RealtimeMCPToolExecutionError", "azure.ai.projects.models.RealtimeReasoning": "OpenAI.RealtimeReasoning", + "azure.ai.projects.models.RealtimeResponseInputAudio": "OpenAI.RealtimeResponseInputAudio", + "azure.ai.projects.models.RealtimeResponseInputFunctionCall": "OpenAI.RealtimeResponseInputFunctionCall", + "azure.ai.projects.models.RealtimeResponseInputFunctionCallOutput": "OpenAI.RealtimeResponseInputFunctionCallOutput", + "azure.ai.projects.models.RealtimeResponseInputImage": "OpenAI.RealtimeResponseInputImage", + "azure.ai.projects.models.RealtimeResponseInputMessage": "OpenAI.RealtimeResponseInputMessage", + "azure.ai.projects.models.RealtimeResponseInputMessageAssistant": "OpenAI.RealtimeResponseInputMessageAssistant", + "azure.ai.projects.models.RealtimeResponseInputMessageAssistantContent": "OpenAI.RealtimeResponseInputMessageAssistantContent", + "azure.ai.projects.models.RealtimeResponseInputMessageDeveloper": "OpenAI.RealtimeResponseInputMessageDeveloper", + "azure.ai.projects.models.RealtimeResponseInputMessageSystem": "OpenAI.RealtimeResponseInputMessageSystem", + "azure.ai.projects.models.RealtimeResponseInputMessageUser": "OpenAI.RealtimeResponseInputMessageUser", + "azure.ai.projects.models.RealtimeResponseInputText": "OpenAI.RealtimeResponseInputText", + "azure.ai.projects.models.RealtimeResponseItemReference": "OpenAI.RealtimeResponseItemReference", "azure.ai.projects.models.RealtimeResponseStatusDetails": "OpenAI.RealtimeResponseStatusDetails", "azure.ai.projects.models.RealtimeResponseStatusDetailsError": "OpenAI.RealtimeResponseStatusDetailsError", "azure.ai.projects.models.RealtimeResponseUsage": "OpenAI.RealtimeResponseUsage", @@ -469,6 +634,7 @@ "azure.ai.projects.models.ResponsesProtocolConfiguration": "Azure.AI.Projects.ResponsesProtocolConfiguration", "azure.ai.projects.models.ResponseUsageInputTokensDetails": "OpenAI.ResponseUsageInputTokensDetails", "azure.ai.projects.models.ResponseUsageOutputTokensDetails": "OpenAI.ResponseUsageOutputTokensDetails", + "azure.ai.projects.models.ResponseUsageResource": "OpenAI.ResponseUsageResource", "azure.ai.projects.models.Routine": "Azure.AI.Projects.Routine", "azure.ai.projects.models.RoutineAuthorization": "Azure.AI.Projects.RoutineAuthorization", "azure.ai.projects.models.RoutineRun": "Azure.AI.Projects.RoutineRun", @@ -478,6 +644,7 @@ "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.ScoreProbabilityResource": "OpenAI.ScoreProbabilityResource", "azure.ai.projects.models.SessionConfiguration": "Azure.AI.Projects.SessionConfiguration", "azure.ai.projects.models.SessionDirectoryEntry": "Azure.AI.Projects.SessionDirectoryEntry", "azure.ai.projects.models.SessionFileWriteResult": "Azure.AI.Projects.SessionFileWriteResponse", @@ -487,7 +654,11 @@ "azure.ai.projects.models.ShellToolboxTool": "Azure.AI.Projects.ShellToolboxTool", "azure.ai.projects.models.SimpleQnADataGenerationJobConfiguration": "Azure.AI.Projects.SimpleQnADataGenerationJobConfiguration", "azure.ai.projects.models.SimulationSeedDataGenerationJobConfiguration": "Azure.AI.Projects.SimulationSeedDataGenerationJobConfiguration", - "azure.ai.projects.models.SipTelephonyTransferDestination": "Azure.AI.Projects.SipTelephonyTransferDestination", + "azure.ai.projects.models.SipAddress": "Azure.AI.Projects.SipAddress", + "azure.ai.projects.models.TelephonyBinding": "Azure.AI.Projects.TelephonyBinding", + "azure.ai.projects.models.SipTelephonyBinding": "Azure.AI.Projects.SipTelephonyBinding", + "azure.ai.projects.models.TelephonyBindingListItem": "Azure.AI.Projects.TelephonyBindingListItem", + "azure.ai.projects.models.SipTelephonyBindingListItem": "Azure.AI.Projects.SipTelephonyBindingListItem", "azure.ai.projects.models.SkillDetails": "Azure.AI.Projects.Skill", "azure.ai.projects.models.SkillInlineContent": "Azure.AI.Projects.SkillInlineContent", "azure.ai.projects.models.SkillReference": "Azure.AI.Projects.SkillReference", @@ -505,23 +676,25 @@ "azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration": "Azure.AI.Projects.SupervisedFineTuningDataGenerationJobOutputConfiguration", "azure.ai.projects.models.TaxonomyCategory": "Azure.AI.Projects.TaxonomyCategory", "azure.ai.projects.models.TaxonomySubCategory": "Azure.AI.Projects.TaxonomySubCategory", - "azure.ai.projects.models.TelephonyBinding": "Azure.AI.Projects.TelephonyBinding", + "azure.ai.projects.models.TeamsAddress": "Azure.AI.Projects.TeamsAddress", "azure.ai.projects.models.TeamsPhoneExtensibilityTelephonyBinding": "Azure.AI.Projects.TeamsPhoneExtensibilityTelephonyBinding", - "azure.ai.projects.models.TelephonyBindingListItem": "Azure.AI.Projects.TelephonyBindingListItem", "azure.ai.projects.models.TeamsPhoneExtensibilityTelephonyBindingListItem": "Azure.AI.Projects.TeamsPhoneExtensibilityTelephonyBindingListItem", - "azure.ai.projects.models.TeamsTelephonyTransferDestination": "Azure.AI.Projects.TeamsTelephonyTransferDestination", "azure.ai.projects.models.TelemetryConfig": "Azure.AI.Projects.TelemetryConfig", "azure.ai.projects.models.TelephonyCallJob": "Azure.AI.Projects.TelephonyCallJob", "azure.ai.projects.models.TelephonyCallJobCancellation": "Azure.AI.Projects.TelephonyCallJobCancellation", + "azure.ai.projects.models.TelephonyCallJobCreate": "Azure.AI.Projects.TelephonyCallJobCreate", "azure.ai.projects.models.TelephonyCallJobSchedule": "Azure.AI.Projects.TelephonyCallJobSchedule", "azure.ai.projects.models.TelephonyCallLifecycleEvent": "Azure.AI.Projects.TelephonyCallLifecycleEvent", "azure.ai.projects.models.TelephonyCallRecord": "Azure.AI.Projects.TelephonyCallRecord", "azure.ai.projects.models.TelephonyCallSummary": "Azure.AI.Projects.TelephonyCallSummary", "azure.ai.projects.models.TelephonyCallTiming": "Azure.AI.Projects.TelephonyCallTiming", "azure.ai.projects.models.TelephonyCallTrace": "Azure.AI.Projects.TelephonyCallTrace", - "azure.ai.projects.models.TelephonyOutboundDestination": "Azure.AI.Projects.TelephonyOutboundDestination", - "azure.ai.projects.models.TelephonyOutboundRetryPolicy": "Azure.AI.Projects.TelephonyOutboundRetryPolicy", - "azure.ai.projects.models.TelephonyOutboundFixedIntervalRetryPolicy": "Azure.AI.Projects.TelephonyOutboundFixedIntervalRetryPolicy", + "azure.ai.projects.models.TelephonyCampaign": "Azure.AI.Projects.TelephonyCampaign", + "azure.ai.projects.models.TelephonyCampaignDatasetReference": "Azure.AI.Projects.DatasetReference", + "azure.ai.projects.models.TelephonyCampaignOperation": "Azure.AI.Projects.TelephonyCampaignOperation", + "azure.ai.projects.models.TelephonyCampaignProgress": "Azure.AI.Projects.TelephonyCampaignProgress", + "azure.ai.projects.models.TelephonyCampaignValidationError": "Azure.AI.Projects.TelephonyCampaignValidationError", + "azure.ai.projects.models.TelephonyRecipient": "Azure.AI.Projects.TelephonyRecipient", "azure.ai.projects.models.TelephonyTransferTarget": "Azure.AI.Projects.TelephonyTransferTarget", "azure.ai.projects.models.TelephonyTransferTargets": "Azure.AI.Projects.TelephonyTransferTargets", "azure.ai.projects.models.TextResponseFormat": "OpenAI.TextResponseFormatConfiguration", @@ -557,7 +730,7 @@ "azure.ai.projects.models.ToolDescription": "Azure.AI.Projects.ToolDescription", "azure.ai.projects.models.ToolProjectConnection": "Azure.AI.Projects.ToolProjectConnection", "azure.ai.projects.models.ToolSearchToolboxTool": "Azure.AI.Projects.ToolSearchToolboxTool", - "azure.ai.projects.models.ToolSearchToolParam": "OpenAI.ToolSearchToolParam", + "azure.ai.projects.models.ToolSearchToolParam": "OpenAI.ToolToolSearchToolParam", "azure.ai.projects.models.ToolUseFineTuningDataGenerationJobConfiguration": "Azure.AI.Projects.ToolUseFineTuningDataGenerationJobConfiguration", "azure.ai.projects.models.TracesDataGenerationJobConfiguration": "Azure.AI.Projects.TracesDataGenerationJobConfiguration", "azure.ai.projects.models.TracesDataGenerationJobSource": "Azure.AI.Projects.TracesDataGenerationJobSource", @@ -584,6 +757,7 @@ "azure.ai.projects.models.VoiceAgentAnimationConfig": "Azure.AI.Projects.VoiceAgentAnimationConfig", "azure.ai.projects.models.VoiceAgentAudioConfig": "Azure.AI.Projects.VoiceAgentAudioConfig", "azure.ai.projects.models.VoiceAgentAudioInputConfig": "Azure.AI.Projects.VoiceAgentAudioInputConfig", + "azure.ai.projects.models.VoiceAgentVoiceConfig": "Azure.AI.Projects.VoiceAgentVoiceConfig", "azure.ai.projects.models.VoiceAgentAudioOutputConfig": "Azure.AI.Projects.VoiceAgentAudioOutputConfig", "azure.ai.projects.models.VoiceAgentAvatarConfig": "Azure.AI.Projects.VoiceAgentAvatarConfig", "azure.ai.projects.models.VoiceAgentAvatarIceServer": "Azure.AI.Projects.VoiceAgentAvatarIceServer", @@ -596,27 +770,71 @@ "azure.ai.projects.models.VoiceAgentAzureSemanticVadEnTurnDetection": "Azure.AI.Projects.VoiceAgentAzureSemanticVadEnTurnDetection", "azure.ai.projects.models.VoiceAgentAzureSemanticVadMultilingualTurnDetection": "Azure.AI.Projects.VoiceAgentAzureSemanticVadMultilingualTurnDetection", "azure.ai.projects.models.VoiceAgentAzureSemanticVadTurnDetection": "Azure.AI.Projects.VoiceAgentAzureSemanticVadTurnDetection", + "azure.ai.projects.models.VoiceAgentBaseDefinition": "Azure.AI.Projects.VoiceAgentBaseDefinition", "azure.ai.projects.models.VoiceAgentClientEventRtcCallSdpCreate": "Azure.AI.Projects.VoiceAgentClientEventRtcCallSdpCreate", "azure.ai.projects.models.VoiceAgentClientEventSessionAvatarConnect": "Azure.AI.Projects.VoiceAgentClientEventSessionAvatarConnect", "azure.ai.projects.models.VoiceAgentClientEventSessionUpdate": "Azure.AI.Projects.VoiceAgentClientEventSessionUpdate", - "azure.ai.projects.models.VoiceAgentDefinition": "Azure.AI.Projects.VoiceAgentDefinition", - "azure.ai.projects.models.VoiceAgentEchoCancellation": "Azure.AI.Projects.VoiceAgentEchoCancellation", + "azure.ai.projects.models.VoiceAgentCollectDtmfStartArguments": "Azure.AI.Projects.VoiceAgentCollectDtmfStartArguments", "azure.ai.projects.models.VoiceAgentTool": "Azure.AI.Projects.VoiceAgentTool", "azure.ai.projects.models.VoiceAgentSystemTool": "Azure.AI.Projects.VoiceAgentSystemTool", + "azure.ai.projects.models.VoiceAgentCollectDtmfSystemTool": "Azure.AI.Projects.VoiceAgentCollectDtmfSystemTool", + "azure.ai.projects.models.VoiceAgentCollectionStartArguments": "Azure.AI.Projects.VoiceAgentCollectionStartArguments", + "azure.ai.projects.models.VoiceAgentCollectSmsStartArguments": "Azure.AI.Projects.VoiceAgentCollectSmsStartArguments", + "azure.ai.projects.models.VoiceAgentCollectSmsSystemTool": "Azure.AI.Projects.VoiceAgentCollectSmsSystemTool", + "azure.ai.projects.models.VoiceAgentDefinition": "Azure.AI.Projects.VoiceAgentDefinition", + "azure.ai.projects.models.VoiceAgentSubagentConfig": "Azure.AI.Projects.VoiceAgentSubagentConfig", + "azure.ai.projects.models.VoiceAgentDelegateSubagentConfig": "Azure.AI.Projects.VoiceAgentDelegateSubagentConfig", + "azure.ai.projects.models.VoiceAgentDigitRecognitionSystemTool": "Azure.AI.Projects.VoiceAgentDigitRecognitionSystemTool", + "azure.ai.projects.models.VoiceAgentDtmfFixedLengthCompletionMode": "Azure.AI.Projects.VoiceAgentDtmfFixedLengthCompletionMode", + "azure.ai.projects.models.VoiceAgentDtmfInterDigitSilenceCompletionMode": "Azure.AI.Projects.VoiceAgentDtmfInterDigitSilenceCompletionMode", + "azure.ai.projects.models.VoiceAgentDtmfTerminatorCompletionMode": "Azure.AI.Projects.VoiceAgentDtmfTerminatorCompletionMode", + "azure.ai.projects.models.VoiceAgentEchoCancellation": "Azure.AI.Projects.VoiceAgentEchoCancellation", "azure.ai.projects.models.VoiceAgentEndConversationSystemTool": "Azure.AI.Projects.VoiceAgentEndConversationSystemTool", "azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection": "Azure.AI.Projects.VoiceAgentEndOfUtteranceDetection", + "azure.ai.projects.models.VoiceAgentPostCallDestination": "Azure.AI.Projects.VoiceAgentPostCallDestination", + "azure.ai.projects.models.VoiceAgentEventGridPostCallDestination": "Azure.AI.Projects.VoiceAgentEventGridPostCallDestination", "azure.ai.projects.models.VoiceAgentFunctionTool": "Azure.AI.Projects.VoiceAgentFunctionTool", "azure.ai.projects.models.VoiceAgentGreetingConfig": "Azure.AI.Projects.VoiceAgentGreetingConfig", + "azure.ai.projects.models.VoiceAgentHandoffCondition": "Azure.AI.Projects.VoiceAgentHandoffCondition", + "azure.ai.projects.models.VoiceAgentHandoffEdgeState": "Azure.AI.Projects.VoiceAgentHandoffEdgeState", + "azure.ai.projects.models.VoiceAgentHandoffNodeState": "Azure.AI.Projects.VoiceAgentHandoffNodeState", + "azure.ai.projects.models.VoiceAgentHandoffPolicy": "Azure.AI.Projects.VoiceAgentHandoffPolicy", + "azure.ai.projects.models.VoiceAgentHandoffState": "Azure.AI.Projects.VoiceAgentHandoffState", + "azure.ai.projects.models.VoiceAgentHandoffVoiceAdaptation": "Azure.AI.Projects.VoiceAgentHandoffVoiceAdaptation", + "azure.ai.projects.models.VoiceAgentInlineSubagentConfig": "Azure.AI.Projects.VoiceAgentInlineSubagentConfig", "azure.ai.projects.models.VoiceAgentInputTranscription": "Azure.AI.Projects.VoiceAgentInputTranscription", "azure.ai.projects.models.VoiceAgentInterimResponseConfig": "Azure.AI.Projects.VoiceAgentInterimResponseConfig", + "azure.ai.projects.models.VoiceAgentLanguageDetectionArguments": "Azure.AI.Projects.VoiceAgentLanguageDetectionArguments", + "azure.ai.projects.models.VoiceAgentLanguageDetectionSystemTool": "Azure.AI.Projects.VoiceAgentLanguageDetectionSystemTool", + "azure.ai.projects.models.VoiceAgentLiveDelegation": "Azure.AI.Projects.VoiceAgentLiveDelegation", + "azure.ai.projects.models.VoiceAgentLiveClientDelegation": "Azure.AI.Projects.VoiceAgentLiveClientDelegation", + "azure.ai.projects.models.VoiceAgentLiveConversationItem": "Azure.AI.Projects.VoiceAgentLiveConversationItem", + "azure.ai.projects.models.VoiceAgentLiveDelegationConversationItem": "Azure.AI.Projects.VoiceAgentLiveDelegationConversationItem", + "azure.ai.projects.models.VoiceAgentLiveClientDelegationConversationItem": "Azure.AI.Projects.VoiceAgentLiveClientDelegationConversationItem", + "azure.ai.projects.models.VoiceAgentLiveConversation": "Azure.AI.Projects.VoiceAgentLiveConversation", + "azure.ai.projects.models.VoiceAgentLiveDefinition": "Azure.AI.Projects.VoiceAgentLiveDefinition", + "azure.ai.projects.models.VoiceAgentLiveDelegationItem": "Azure.AI.Projects.VoiceAgentLiveDelegationItem", + "azure.ai.projects.models.VoiceAgentLiveDelegationResultItem": "Azure.AI.Projects.VoiceAgentLiveDelegationResultItem", + "azure.ai.projects.models.VoiceAgentLiveFoundryManagedAgentDelegationItem": "Azure.AI.Projects.VoiceAgentLiveFoundryManagedAgentDelegationItem", + "azure.ai.projects.models.VoiceAgentLiveInputConversationItem": "Azure.AI.Projects.VoiceAgentLiveInputConversationItem", + "azure.ai.projects.models.VoiceAgentLiveManagedAgentDelegation": "Azure.AI.Projects.VoiceAgentLiveManagedAgentDelegation", + "azure.ai.projects.models.VoiceAgentLiveOutputConversationItem": "Azure.AI.Projects.VoiceAgentLiveOutputConversationItem", + "azure.ai.projects.models.VoiceAgentLiveResponsesDelegation": "Azure.AI.Projects.VoiceAgentLiveResponsesDelegation", + "azure.ai.projects.models.VoiceAgentLiveResponsesDelegationConversationItem": "Azure.AI.Projects.VoiceAgentLiveResponsesDelegationConversationItem", + "azure.ai.projects.models.VoiceAgentLiveSessionResource": "Azure.AI.Projects.VoiceAgentLiveSessionResource", "azure.ai.projects.models.VoiceAgentLlmGeneratedGreetingConfig": "Azure.AI.Projects.VoiceAgentLlmGeneratedGreetingConfig", "azure.ai.projects.models.VoiceAgentLlmInterimResponseConfig": "Azure.AI.Projects.VoiceAgentLlmInterimResponseConfig", "azure.ai.projects.models.VoiceAgentMcpTool": "Azure.AI.Projects.VoiceAgentMcpTool", "azure.ai.projects.models.VoiceAgentNoiseReduction": "Azure.AI.Projects.VoiceAgentNoiseReduction", + "azure.ai.projects.models.VoiceAgentPostCallConfig": "Azure.AI.Projects.VoiceAgentPostCallConfig", "azure.ai.projects.models.VoiceAgentRealtimeResponse": "Azure.AI.Projects.VoiceAgentRealtimeResponse", "azure.ai.projects.models.VoiceAgentResponseCreateParams": "Azure.AI.Projects.VoiceAgentResponseCreateParams", + "azure.ai.projects.models.VoiceAgentRoutinePostCallDestination": "Azure.AI.Projects.VoiceAgentRoutinePostCallDestination", "azure.ai.projects.models.VoiceAgentRtcCallErrorDetails": "Azure.AI.Projects.VoiceAgentRtcCallErrorDetails", "azure.ai.projects.models.VoiceAgentSemanticVadTurnDetection": "Azure.AI.Projects.VoiceAgentSemanticVadTurnDetection", + "azure.ai.projects.models.VoiceAgentSendDtmfSystemTool": "Azure.AI.Projects.VoiceAgentSendDtmfSystemTool", + "azure.ai.projects.models.VoiceAgentSendSmsSystemTool": "Azure.AI.Projects.VoiceAgentSendSmsSystemTool", + "azure.ai.projects.models.VoiceAgentServerEventInputCollectionStatus": "Azure.AI.Projects.VoiceAgentServerEventInputCollectionStatus", "azure.ai.projects.models.VoiceAgentServerEventResponseAnimationBlendshapesDelta": "Azure.AI.Projects.VoiceAgentServerEventResponseAnimationBlendshapesDelta", "azure.ai.projects.models.VoiceAgentServerEventResponseAnimationBlendshapesDone": "Azure.AI.Projects.VoiceAgentServerEventResponseAnimationBlendshapesDone", "azure.ai.projects.models.VoiceAgentServerEventResponseAnimationVisemeDelta": "Azure.AI.Projects.VoiceAgentServerEventResponseAnimationVisemeDelta", @@ -629,9 +847,14 @@ "azure.ai.projects.models.VoiceAgentServerEventSessionAvatarConnecting": "Azure.AI.Projects.VoiceAgentServerEventSessionAvatarConnecting", "azure.ai.projects.models.VoiceAgentServerEventSessionAvatarSwitchToIdle": "Azure.AI.Projects.VoiceAgentServerEventSessionAvatarSwitchToIdle", "azure.ai.projects.models.VoiceAgentServerEventSessionAvatarSwitchToSpeaking": "Azure.AI.Projects.VoiceAgentServerEventSessionAvatarSwitchToSpeaking", + "azure.ai.projects.models.VoiceAgentServerEventSessionHandoffAborted": "Azure.AI.Projects.VoiceAgentServerEventSessionHandoffAborted", + "azure.ai.projects.models.VoiceAgentServerEventSessionHandoffCompleted": "Azure.AI.Projects.VoiceAgentServerEventSessionHandoffCompleted", + "azure.ai.projects.models.VoiceAgentServerEventSessionHandoffStarted": "Azure.AI.Projects.VoiceAgentServerEventSessionHandoffStarted", "azure.ai.projects.models.VoiceAgentServerEventSessionSubagentAborted": "Azure.AI.Projects.VoiceAgentServerEventSessionSubagentAborted", "azure.ai.projects.models.VoiceAgentServerEventSessionSubagentCompleted": "Azure.AI.Projects.VoiceAgentServerEventSessionSubagentCompleted", "azure.ai.projects.models.VoiceAgentServerEventSessionSubagentStarted": "Azure.AI.Projects.VoiceAgentServerEventSessionSubagentStarted", + "azure.ai.projects.models.VoiceAgentServerEventSystemToolArgumentsDelta": "Azure.AI.Projects.VoiceAgentServerEventSystemToolArgumentsDelta", + "azure.ai.projects.models.VoiceAgentServerEventSystemToolArgumentsDone": "Azure.AI.Projects.VoiceAgentServerEventSystemToolArgumentsDone", "azure.ai.projects.models.VoiceAgentServerEventWarning": "Azure.AI.Projects.VoiceAgentServerEventWarning", "azure.ai.projects.models.VoiceAgentServerEventWarningDetails": "Azure.AI.Projects.VoiceAgentServerEventWarningDetails", "azure.ai.projects.models.VoiceAgentServerVadTurnDetection": "Azure.AI.Projects.VoiceAgentServerVadTurnDetection", @@ -644,12 +867,16 @@ "azure.ai.projects.models.VoiceAgentSoundscapeWorkingTrackConfig": "Azure.AI.Projects.VoiceAgentSoundscapeWorkingTrackConfig", "azure.ai.projects.models.VoiceAgentStaticInterimResponseConfig": "Azure.AI.Projects.VoiceAgentStaticInterimResponseConfig", "azure.ai.projects.models.VoiceAgentSubagent": "Azure.AI.Projects.VoiceAgentSubagent", - "azure.ai.projects.models.VoiceAgentSubagentConfig": "Azure.AI.Projects.VoiceAgentSubagentConfig", "azure.ai.projects.models.VoiceAgentSubagentResponsePolicy": "Azure.AI.Projects.VoiceAgentSubagentResponsePolicy", + "azure.ai.projects.models.VoiceAgentSystemToolItem": "Azure.AI.Projects.VoiceAgentSystemToolItem", "azure.ai.projects.models.VoiceAgentTemplateGreetingConfig": "Azure.AI.Projects.VoiceAgentTemplateGreetingConfig", "azure.ai.projects.models.VoiceAgentToolboxTool": "Azure.AI.Projects.VoiceAgentToolboxTool", "azure.ai.projects.models.VoiceAgentTranscriptionPhrase": "Azure.AI.Projects.VoiceAgentTranscriptionPhrase", "azure.ai.projects.models.VoiceAgentTranscriptionWord": "Azure.AI.Projects.VoiceAgentTranscriptionWord", + "azure.ai.projects.models.VoiceAgentTransferDestination": "Azure.AI.Projects.VoiceAgentTransferDestination", + "azure.ai.projects.models.VoiceAgentTransferRouting": "Azure.AI.Projects.VoiceAgentTransferRouting", + "azure.ai.projects.models.VoiceAgentTransferSystemTool": "Azure.AI.Projects.VoiceAgentTransferSystemTool", + "azure.ai.projects.models.VoiceAgentTransferTarget": "Azure.AI.Projects.VoiceAgentTransferTarget", "azure.ai.projects.models.VoiceAudioItem": "Azure.AI.Projects.VoiceAudioItem", "azure.ai.projects.models.VoiceConversation": "Azure.AI.Projects.VoiceConversation", "azure.ai.projects.models.VoiceConversationEngine": "Azure.AI.Projects.VoiceConversationEngine", @@ -664,8 +891,8 @@ "azure.ai.projects.models.WebIQPreviewToolboxTool": "Azure.AI.Projects.WebIQPreviewToolboxTool", "azure.ai.projects.models.WebSearchApproximateLocation": "OpenAI.WebSearchApproximateLocation", "azure.ai.projects.models.WebSearchConfiguration": "Azure.AI.Projects.WebSearchConfiguration", - "azure.ai.projects.models.WebSearchPreviewTool": "OpenAI.WebSearchPreviewTool", - "azure.ai.projects.models.WebSearchTool": "OpenAI.WebSearchTool", + "azure.ai.projects.models.WebSearchPreviewTool": "OpenAI.ToolWebSearchPreviewTool", + "azure.ai.projects.models.WebSearchTool": "OpenAI.ToolWebSearchTool", "azure.ai.projects.models.WebSearchToolboxTool": "Azure.AI.Projects.WebSearchToolboxTool", "azure.ai.projects.models.WebSearchToolFilters": "OpenAI.WebSearchToolFilters", "azure.ai.projects.models.WeeklyRecurrenceSchedule": "Azure.AI.Projects.WeeklyRecurrenceSchedule", @@ -678,13 +905,18 @@ "azure.ai.projects.models.RealtimeConversationItemType": "OpenAI.RealtimeConversationItemType", "azure.ai.projects.models.RealtimeMcpErrorType": "OpenAI.RealtimeMcpErrorType", "azure.ai.projects.models.RealtimeConversationItemMessageType": "OpenAI.RealtimeConversationItemMessageType", + "azure.ai.projects.models.VoiceAgentConversationItemTypeExtension": "Azure.AI.Projects.VoiceAgentConversationItemTypeExtension", + "azure.ai.projects.models.VoiceAgentSystemToolItemStatus": "Azure.AI.Projects.VoiceAgentSystemToolItemStatus", + "azure.ai.projects.models.VoiceAgentSystemToolName": "Azure.AI.Projects.VoiceAgentSystemToolName", "azure.ai.projects.models.VoiceType": "Azure.AI.Projects.VoiceType", "azure.ai.projects.models.RealtimeAudioFormatsType": "OpenAI.RealtimeAudioFormatsType", "azure.ai.projects.models.VoiceAudioRole": "Azure.AI.Projects.VoiceAudioRole", "azure.ai.projects.models.VoiceAudioContainerFormat": "Azure.AI.Projects.VoiceAudioContainerFormat", "azure.ai.projects.models.VoiceAudioCodec": "Azure.AI.Projects.VoiceAudioCodec", + "azure.ai.projects.models.VoiceAgentLiveConversationItemType": "Azure.AI.Projects.VoiceAgentLiveConversationItemType", + "azure.ai.projects.models.VoiceAgentLiveDelegationTarget": "Azure.AI.Projects.VoiceAgentLiveDelegationTarget", + "azure.ai.projects.models.VoiceAgentLiveDelegationStatus": "Azure.AI.Projects.VoiceAgentLiveDelegationStatus", "azure.ai.projects.models.TelephonyProvider": "Azure.AI.Projects.TelephonyProvider", - "azure.ai.projects.models.TelephonyBindingStatus": "Azure.AI.Projects.TelephonyBindingStatus", "azure.ai.projects.models.TelephonyCallStatus": "Azure.AI.Projects.TelephonyCallStatus", "azure.ai.projects.models.TelephonyCallPhase": "Azure.AI.Projects.TelephonyCallPhase", "azure.ai.projects.models.TelephonyCallEndReason": "Azure.AI.Projects.TelephonyCallEndReason", @@ -696,11 +928,14 @@ "azure.ai.projects.models.TelephonyCallLifecycleEventSource": "Azure.AI.Projects.TelephonyCallLifecycleEventSource", "azure.ai.projects.models.TelephonyCallLifecycleEventOutcome": "Azure.AI.Projects.TelephonyCallLifecycleEventOutcome", "azure.ai.projects.models.TelephonyCallLifecycleEventReason": "Azure.AI.Projects.TelephonyCallLifecycleEventReason", - "azure.ai.projects.models.TelephonyTransferDestinationKind": "Azure.AI.Projects.TelephonyTransferDestinationKind", - "azure.ai.projects.models.TelephonyOutboundDestinationType": "Azure.AI.Projects.TelephonyOutboundDestinationType", + "azure.ai.projects.models.TelephonyAddressType": "Azure.AI.Projects.TelephonyAddressType", "azure.ai.projects.models.TelephonyCallJobStatus": "Azure.AI.Projects.TelephonyCallJobStatus", "azure.ai.projects.models.TelephonyOutboundRetryPolicyType": "Azure.AI.Projects.TelephonyOutboundRetryPolicyType", "azure.ai.projects.models.TelephonyCallJobTerminalReason": "Azure.AI.Projects.TelephonyCallJobTerminalReason", + "azure.ai.projects.models.TelephonyCampaignScheduleType": "Azure.AI.Projects.TelephonyCampaignScheduleType", + "azure.ai.projects.models.TelephonyCampaignStatus": "Azure.AI.Projects.TelephonyCampaignStatus", + "azure.ai.projects.models.JobStatus": "Azure.AI.Projects.JobStatus", + "azure.ai.projects.models.TelephonyCampaignOperationKind": "Azure.AI.Projects.TelephonyCampaignOperationKind", "azure.ai.projects.models.AgentObjectType": "Azure.AI.Projects.AgentObjectType", "azure.ai.projects.models.AgentState": "Azure.AI.Projects.AgentState", "azure.ai.projects.models.AgentStateSource": "Azure.AI.Projects.AgentStateSource", @@ -737,7 +972,19 @@ "azure.ai.projects.models.SearchContentType": "OpenAI.SearchContentType", "azure.ai.projects.models.ToolChoiceParamType": "OpenAI.ToolChoiceParamType", "azure.ai.projects.models.TextResponseFormatConfigurationType": "OpenAI.TextResponseFormatConfigurationType", + "azure.ai.projects.models.VoiceAgentSubProtocol": "Azure.AI.Projects.VoiceAgentSubProtocol", "azure.ai.projects.models.VoiceModelType": "Azure.AI.Projects.VoiceModelType", + "azure.ai.projects.models.VoiceAgentGreetingMode": "Azure.AI.Projects.VoiceAgentGreetingMode", + "azure.ai.projects.models.LiveAudioFormatType": "OpenAI.LiveAudioFormatType", + "azure.ai.projects.models.VoiceAgentLiveDelegationType": "Azure.AI.Projects.VoiceAgentLiveDelegationType", + "azure.ai.projects.models.LiveResponsesServiceTier": "OpenAI.LiveResponsesServiceTier", + "azure.ai.projects.models.LiveReasoningEffort": "OpenAI.LiveReasoningEffort", + "azure.ai.projects.models.LiveReasoningSummary": "OpenAI.LiveReasoningSummary", + "azure.ai.projects.models.LiveTextVerbosity": "OpenAI.LiveTextVerbosity", + "azure.ai.projects.models.LiveContainerMemoryLimit": "OpenAI.LiveContainerMemoryLimit", + "azure.ai.projects.models.LiveToolChoiceEnum": "OpenAI.LiveToolChoiceEnum", + "azure.ai.projects.models.LiveToolChoiceValueEnum": "OpenAI.LiveToolChoiceValueEnum", + "azure.ai.projects.models.VoiceConversationEngineType": "Azure.AI.Projects.VoiceConversationEngineType", "azure.ai.projects.models.VoiceAgentNoiseReductionType": "Azure.AI.Projects.VoiceAgentNoiseReductionType", "azure.ai.projects.models.VoiceAgentTurnDetectionType": "Azure.AI.Projects.VoiceAgentTurnDetectionType", "azure.ai.projects.models.VoiceAgentEndOfUtteranceDetectionModel": "Azure.AI.Projects.VoiceAgentEndOfUtteranceDetectionModel", @@ -749,11 +996,19 @@ "azure.ai.projects.models.VoiceAgentSoundscapeSound": "Azure.AI.Projects.VoiceAgentSoundscapeSound", "azure.ai.projects.models.VoiceOutputModality": "Azure.AI.Projects.VoiceOutputModality", "azure.ai.projects.models.VoiceAgentSessionIncludeOption": "Azure.AI.Projects.VoiceAgentSessionIncludeOption", + "azure.ai.projects.models.VoiceAgentInterimResponseType": "Azure.AI.Projects.VoiceAgentInterimResponseType", "azure.ai.projects.models.VoiceAgentInterimResponseTrigger": "Azure.AI.Projects.VoiceAgentInterimResponseTrigger", "azure.ai.projects.models.VoiceAgentAvatarType": "Azure.AI.Projects.VoiceAgentAvatarType", "azure.ai.projects.models.VoiceAgentAvatarOutputProtocol": "Azure.AI.Projects.VoiceAgentAvatarOutputProtocol", + "azure.ai.projects.models.VoiceAgentToolType": "Azure.AI.Projects.VoiceAgentToolType", "azure.ai.projects.models.VoiceAgentToolResponseScheduling": "Azure.AI.Projects.VoiceAgentToolResponseScheduling", - "azure.ai.projects.models.VoiceAgentSystemToolName": "Azure.AI.Projects.VoiceAgentSystemToolName", + "azure.ai.projects.models.VoiceAgentTransferDestinationType": "Azure.AI.Projects.VoiceAgentTransferDestinationType", + "azure.ai.projects.models.VoiceAgentTransferStrategy": "Azure.AI.Projects.VoiceAgentTransferStrategy", + "azure.ai.projects.models.VoiceAgentSubagentType": "Azure.AI.Projects.VoiceAgentSubagentType", + "azure.ai.projects.models.VoiceAgentHandoffReasoningEffort": "Azure.AI.Projects.VoiceAgentHandoffReasoningEffort", + "azure.ai.projects.models.VoiceAgentHandoffTargetResponse": "Azure.AI.Projects.VoiceAgentHandoffTargetResponse", + "azure.ai.projects.models.VoiceAgentPostCallDestinationType": "Azure.AI.Projects.VoiceAgentPostCallDestinationType", + "azure.ai.projects.models.VoiceAgentPostCallIncludeOption": "Azure.AI.Projects.VoiceAgentPostCallIncludeOption", "azure.ai.projects.models.AgentVersionStatus": "Azure.AI.Projects.AgentVersionStatus", "azure.ai.projects.models.AgentIdentityStatus": "Azure.AI.Projects.AgentIdentityStatus", "azure.ai.projects.models.AgentBlueprintReferenceType": "Azure.AI.Projects.AgentBlueprintReferenceType", @@ -763,7 +1018,6 @@ "azure.ai.projects.models.PublishApprovalStatus": "Azure.AI.Projects.PublishApprovalStatus", "azure.ai.projects.models.DigitalWorkerType": "Azure.AI.Projects.DigitalWorkerType", "azure.ai.projects.models.AgentInsightOverviewSource": "Azure.AI.Projects.AgentInsightOverviewSource", - "azure.ai.projects.models.JobStatus": "Azure.AI.Projects.JobStatus", "azure.ai.projects.models.AgentInsightRunTrigger": "Azure.AI.Projects.AgentInsightRunTrigger", "azure.ai.projects.models.AgentInsightSeverity": "Azure.AI.Projects.AgentInsightSeverity", "azure.ai.projects.models.AgentInsightStatus": "Azure.AI.Projects.AgentInsightStatus", @@ -842,11 +1096,33 @@ "azure.ai.projects.models.MemoryStoreUpdateStatus": "Azure.AI.Projects.MemoryStoreUpdateStatus", "azure.ai.projects.models.VoiceAgentAnimationOutputType": "Azure.AI.Projects.VoiceAgentAnimationOutputType", "azure.ai.projects.models.RealtimeReasoningEffort": "OpenAI.RealtimeReasoningEffort", - "azure.ai.projects.models.RealtimeClientEventType": "OpenAI.RealtimeClientEventType", - "azure.ai.projects.models.ToolChoiceOptions": "OpenAI.ToolChoiceOptions", + "azure.ai.projects.models.VoiceAgentHandoffPipelineFamily": "Azure.AI.Projects.VoiceAgentHandoffPipelineFamily", "azure.ai.projects.models.RealtimeServerEventType": "OpenAI.RealtimeServerEventType", "azure.ai.projects.models.CreateTranscriptionResponseJsonUsageType": "OpenAI.CreateTranscriptionResponseJsonUsageType", + "azure.ai.projects.models.VoiceAgentServerEventTypeExtension": "Azure.AI.Projects.VoiceAgentServerEventTypeExtension", + "azure.ai.projects.models.VoiceAgentInputCollectionChannel": "Azure.AI.Projects.VoiceAgentInputCollectionChannel", + "azure.ai.projects.models.VoiceAgentInputCollectionStatus": "Azure.AI.Projects.VoiceAgentInputCollectionStatus", + "azure.ai.projects.models.VoiceAgentRtcCallErrorType": "Azure.AI.Projects.VoiceAgentRtcCallErrorType", + "azure.ai.projects.models.VoiceAgentHandoffAbortReason": "Azure.AI.Projects.VoiceAgentHandoffAbortReason", "azure.ai.projects.models.VoiceAgentSubagentAbortReason": "Azure.AI.Projects.VoiceAgentSubagentAbortReason", + "azure.ai.projects.models.RealtimeClientEventType": "OpenAI.RealtimeClientEventType", + "azure.ai.projects.models.ToolChoiceOptions": "OpenAI.ToolChoiceOptions", + "azure.ai.projects.models.RealtimeResponseInputMessageType": "OpenAI.RealtimeResponseInputMessageType", + "azure.ai.projects.models.VoiceAgentClientEventTypeExtension": "Azure.AI.Projects.VoiceAgentClientEventTypeExtension", + "azure.ai.projects.models.VoiceAgentDtmfTerminator": "Azure.AI.Projects.VoiceAgentDtmfTerminator", + "azure.ai.projects.models.LiveClientEventType": "OpenAI.LiveClientEventType", + "azure.ai.projects.models.LiveDecisionInputItemParamType": "OpenAI.LiveDecisionInputItemParamType", + "azure.ai.projects.models.LiveFunctionCallItemStatus": "OpenAI.LiveFunctionCallItemStatus", + "azure.ai.projects.models.LiveDetailEnum": "OpenAI.LiveDetailEnum", + "azure.ai.projects.models.ModelIdsLive": "OpenAI.ModelIdsLive", + "azure.ai.projects.models.LiveInitialItemType": "OpenAI.LiveInitialItemType", + "azure.ai.projects.models.LiveInitialMessageStatus": "OpenAI.LiveInitialMessageStatus", + "azure.ai.projects.models.LiveSessionCreateParamsDelegationType": "OpenAI.LiveSessionCreateParamsDelegationType", + "azure.ai.projects.models.LiveDecisionQuestionType": "OpenAI.LiveDecisionQuestionType", + "azure.ai.projects.models.LiveSessionUpdateParamsDelegationType": "OpenAI.LiveSessionUpdateParamsDelegationType", + "azure.ai.projects.models.LiveServerEventType": "OpenAI.LiveServerEventType", + "azure.ai.projects.models.AnswerResourceType": "OpenAI.AnswerResourceType", + "azure.ai.projects.models.LiveDecisionStoredInputItemParamType": "OpenAI.LiveDecisionStoredInputItemParamType", "azure.ai.projects.models.VoiceAgentTransport": "Azure.AI.Projects.VoiceAgentTransport", "azure.ai.projects.operations.AgentsOperations.get": "Azure.AI.Projects.Agents.getAgent", "azure.ai.projects.aio.operations.AgentsOperations.get": "Azure.AI.Projects.Agents.getAgent", @@ -1005,5 +1281,5 @@ "azure.ai.projects.operations.ToolboxesOperations.delete_version": "Azure.AI.Projects.Toolboxes.deleteToolboxVersion", "azure.ai.projects.aio.operations.ToolboxesOperations.delete_version": "Azure.AI.Projects.Toolboxes.deleteToolboxVersion" }, - "CrossLanguageVersion": "1c8b2a2c820a" + "CrossLanguageVersion": "3247452fbac8" } \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/assets.json b/sdk/ai/azure-ai-projects/assets.json index 967ce583e174..5f1a62040671 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_5245c1d334" + "Tag": "python/ai/azure-ai-projects_b328dd1d0f" } diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_live.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_live.py new file mode 100644 index 000000000000..c422a984fccb --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_live.py @@ -0,0 +1,288 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- +"""Synchronous GPT Live sessions at ``client.beta.voice_agents.live``.""" + +from __future__ import annotations + +import base64 +from typing import Any, Iterator, Mapping, Optional, TYPE_CHECKING, Union + +from . import models +from ._realtime import _BaseWebSocketConnection, _BaseWebSocketConnectionManager, _ConfigProvider +from ._live_utils import LiveClientEvent, LiveServerEvent, _LOGGER, _SERVER_EVENT_TYPES, _event, _live_query, _live_url + +if TYPE_CHECKING: + from websockets.sync.client import ClientConnection + +__all__ = ["BetaLive", "BetaLiveConnection", "BetaLiveConnectionManager", "LiveClientEvent", "LiveServerEvent"] + + +class _Resource: + def __init__(self, connection: BetaLiveConnection) -> None: + self._connection = connection + + +class TextResource(_Resource): + """Send instructions, unspoken context, or spoken commentary.""" + + def __init__(self, connection: BetaLiveConnection, event_model: type[models.LiveClientEvent]) -> None: + super().__init__(connection) + self._event_model = event_model + + def append(self, *, content: str, delegation_id: Optional[str], event_id: Optional[str] = None) -> None: + """Send text, optionally tied to a request delegated to your app. + + :keyword str content: Text to append. + :keyword delegation_id: The delegated request's ID, or None for standalone text. + :paramtype delegation_id: str or None + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(self._event_model, event_id, content=content, delegation_id=delegation_id)) + + +class InputAudioResource(_Resource): + """Send audio using the session's configured format.""" + + def append(self, *, audio: Union[str, bytes], event_id: Optional[str] = None) -> None: + """Send raw audio bytes or base64 without a container header. + + :keyword audio: Raw audio or an already base64-encoded string. + :paramtype audio: str or bytes + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + encoded = base64.b64encode(audio).decode("ascii") if isinstance(audio, bytes) else audio + self._connection.send(_event(models.LiveClientEventLiveInputAudioAppendEvent, event_id, audio=encoded)) + + def mute(self, *, event_id: Optional[str] = None) -> None: + """Mute input audio processing. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(models.LiveClientEventLiveInputAudioMuteParam, event_id)) + + def unmute(self, *, event_id: Optional[str] = None) -> None: + """Resume input audio processing. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(models.LiveClientEventLiveInputAudioUnmuteParam, event_id)) + + +class SessionResource(_Resource): + """Control a Live session that Foundry starts when the connection opens.""" + + def __init__(self, connection: BetaLiveConnection) -> None: + super().__init__(connection) + self.input_audio = InputAudioResource(connection) + self.instructions = TextResource(connection, models.LiveClientEventLiveInstructionsAppendParam) + self.thinking = TextResource(connection, models.LiveClientEventLiveThinkingAppendParam) + self.commentary = TextResource(connection, models.LiveClientEventLiveCommentaryAppendParam) + + def update( + self, *, session: Union[models.LiveSessionUpdateParams, Mapping[str, Any]], event_id: Optional[str] = None + ) -> None: + """Update backend delegation settings or transcript triggers. + + The persisted Foundry delegation target, frontend model, and audio format cannot change + mid-session. + + :keyword session: The backend settings or transcript triggers to change. + :paramtype session: ~azure.ai.projects.models.LiveSessionUpdateParams or Mapping[str, Any] + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(models.LiveClientEventLiveSessionUpdateParam, event_id, session=session)) + + def close(self, *, event_id: Optional[str] = None) -> None: + """Request graceful session shutdown; receive session.closed before closing the socket. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(models.LiveClientEventLiveSessionCloseParam, event_id)) + + +class ResponseItemResource(_Resource): + """Send user messages or tool results to the Responses backend model.""" + + def create(self, *, item: Mapping[str, Any], event_id: Optional[str] = None) -> None: + """Send a message or tool result. Requires a Responses backend. + + :keyword item: Responses input item, including function_call_output. + :paramtype item: Mapping[str, Any] + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(models.LiveClientEventLiveResponseItemCreateParam, event_id, item=dict(item))) + + +class ResponseResource(_Resource): + """Request replies from the Responses backend model.""" + + def __init__(self, connection: BetaLiveConnection) -> None: + super().__init__(connection) + self.item = ResponseItemResource(connection) + + def create(self, *, event_id: Optional[str] = None) -> None: + """Request or continue a backend response after submitting tool results. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + self._connection.send(_event(models.LiveClientEventLiveResponseCreateParam, event_id)) + + +class BetaLiveConnection(_BaseWebSocketConnection[LiveServerEvent, LiveClientEvent]): + """Send and receive events on a GPT Live connection. + + Service errors arrive as error events. Use the context manager to close + the connection. Send ``session.close`` to end the session; Live has no + ``response.cancel`` command. + """ + + _logger = _LOGGER + _server_event_types = _SERVER_EVENT_TYPES + _protocol_name = "Live" + + def __init__(self, connection: ClientConnection) -> None: + super().__init__(connection) + self.session = SessionResource(self) + self.response = ResponseResource(self) + + def __enter__(self) -> BetaLiveConnection: + return self + + def __iter__(self) -> Iterator[LiveServerEvent]: + return self._iter() + + def recv(self, *, timeout: Optional[float] = None) -> LiveServerEvent: + """Receive an SDK event model, or a dictionary for an unknown event type. + + :keyword timeout: Maximum receive wait in seconds; None waits indefinitely. + :paramtype timeout: float or None + :return: The server event. + :rtype: ~azure.ai.projects.operations.LiveServerEvent + :raises ConnectionResetError: On graceful or abnormal socket closure. + :raises TimeoutError: When the receive deadline expires. + """ + return super().recv(timeout=timeout) + + def send(self, event: LiveClientEvent) -> None: + """Send an SDK event model, mapping, or JSON string. + + :param event: The client event. + :type event: ~azure.ai.projects.operations.LiveClientEvent + :raises ValueError: If the supplied JSON string is invalid. + """ + super().send(dict(event) if isinstance(event, Mapping) else event) + + +class BetaLiveConnectionManager(_BaseWebSocketConnectionManager[BetaLiveConnection]): + """Context manager for one Live session using the project's credential.""" + + _logger = _LOGGER + _subprotocol = None + _protocol_name = "Live" + + def __init__( + self, + *, + agent_version: Optional[str] = None, + store: Optional[bool] = None, + **kwargs: Any, + ) -> None: + super().__init__(**kwargs) + self._agent_version = agent_version + self._store = store + + def __enter__(self) -> BetaLiveConnection: + return self.enter() + + def enter(self) -> BetaLiveConnection: + """Open the connection. Foundry starts the Live session automatically. + + :return: The Live connection. + :rtype: ~azure.ai.projects.operations.BetaLiveConnection + """ + return super().enter() + + def _get_url(self) -> str: + return _live_url(self._endpoint, self._agent_name) + + def _get_query(self) -> dict[str, str]: + return _live_query( + self._api_version, self._agent_version, self._structured_inputs, self._store, self._extra_query + ) + + def _create_connection(self, connection: ClientConnection) -> BetaLiveConnection: + return BetaLiveConnection(connection) + + +class BetaLive: + """Connect to GPT Live through ``client.beta.voice_agents.live``. + + Foundry starts the session from the saved agent settings. Wait for + ``session.started`` before sending commands; do not send ``session.start``. + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + input_args = list(args) + client: _ConfigProvider = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = client._config # pylint: disable=protected-access + + def connect( + self, + *, + agent_name: str, + agent_version: Optional[str] = None, + structured_inputs: Optional[Mapping[str, Any]] = None, + store: Optional[bool] = None, + connection_url: Optional[str] = None, + api_version: Optional[str] = None, + credential_scopes: Optional[list[str]] = None, + extra_query: Optional[Mapping[str, str]] = None, + extra_headers: Optional[Mapping[str, str]] = None, + **kwargs: Any, + ) -> BetaLiveConnectionManager: + """Connect to a GPT Live agent when entering the context manager. + + :keyword str agent_name: The name of an existing GPT Live agent. + :keyword agent_version: A specific agent version, if needed. + :paramtype agent_version: str or None + :keyword structured_inputs: Values for placeholders in the agent's instructions and greeting. + :paramtype structured_inputs: Mapping[str, Any] or None + :keyword store: Save conversation content and audio. None uses the agent's setting. + :paramtype store: bool or None + :keyword connection_url: A wss URL on the project endpoint's origin, instead of the default route. + :paramtype connection_url: str or None + :keyword api_version: API version override. + :paramtype api_version: str or None + :keyword credential_scopes: Token scope override. + :paramtype credential_scopes: list[str] or None + :keyword extra_query: Additional handshake query values. + :paramtype extra_query: Mapping[str, str] or None + :keyword extra_headers: Additional handshake headers. + :paramtype extra_headers: Mapping[str, str] or None + :return: A Live connection context manager. + :rtype: ~azure.ai.projects.operations.BetaLiveConnectionManager + """ + return BetaLiveConnectionManager( + endpoint=self._config.endpoint, + credential=self._config.credential, + credential_scopes=credential_scopes or self._config.credential_scopes, + api_version=api_version or self._config.api_version, + agent_name=agent_name, + agent_version=agent_version, + structured_inputs=structured_inputs, + store=store, + connection_url=connection_url, + extra_query=extra_query, + extra_headers=extra_headers, + **kwargs, + ) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_live_utils.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_live_utils.py new file mode 100644 index 000000000000..84a494d2f403 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_live_utils.py @@ -0,0 +1,67 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- +"""Shared protocol metadata for the handwritten Live clients. + +Foundry constructs session.start from the persisted agent definition. Live uses +its own event vocabulary; Realtime response.cancel and audio-buffer commands +must not be synthesized on this connection. +""" + +import json +import logging +from typing import Any, Mapping, Optional, Type, Union + +from . import models +from ._realtime import _to_ws_url, _USER_AGENT +from ._utils.model_base import Model, SdkJSONEncoder + +LiveClientEvent = Union[models.LiveClientEvent, str, Mapping[str, Any]] +LiveServerEvent = Union[models.LiveServerEvent, Mapping[str, Any]] +_LOGGER = logging.getLogger("azure.ai.projects.live") + + +def _server_event_types(registry: Mapping[str, object]) -> dict[str, Type[Model]]: + result: dict[str, Type[Model]] = {} + for name, cls in registry.items(): + if isinstance(cls, type) and issubclass(cls, Model): + result[name] = cls + return result + + +_SERVER_EVENT_TYPES = _server_event_types(models.LiveServerEvent.__mapping__) + + +def _live_url(endpoint: str, agent_name: str) -> str: + return _to_ws_url(endpoint, agent_name) + "/live/sessions" + + +def _live_query( + api_version: str, + agent_version: Optional[str], + structured_inputs: Optional[Mapping[str, Any]], + store: Optional[bool], + extra_query: Mapping[str, str], +) -> dict[str, str]: + result = {"api-version": api_version, "x-ms-client-sdk": _USER_AGENT} + result.update(extra_query) + if agent_version is not None: + result["agent_version_override"] = agent_version + if structured_inputs is not None: + if "structured_input" in result: + raise ValueError("structured_input and structured_inputs cannot be supplied together.") + result["structured_inputs"] = json.dumps(dict(structured_inputs), cls=SdkJSONEncoder) + if "structured_inputs" in result and "structured_input" in result: + raise ValueError("structured_input and structured_inputs cannot be supplied together.") + if store is not None: + result["store"] = str(store).lower() + return result + + +def _event( + model: Type[models.LiveClientEvent], event_id: Optional[str] = None, **fields: Any +) -> models.LiveClientEvent: + if event_id is not None: + fields["event_id"] = event_id + return model(fields) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_realtime.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_realtime.py index d492b10b4d01..c56df2557880 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_realtime.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_realtime.py @@ -1,18 +1,14 @@ -# pylint: disable=networking-import-outside-azure-core-transport +# pylint: disable=networking-import-outside-azure-core-transport,too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------- -"""Hand-written sync realtime (WebSocket) streaming client for voice agents. +"""Synchronous Realtime voice-agent client. -This is the synchronous counterpart of :mod:`azure.ai.projects.aio._realtime`. See that -module's docstring for the full design rationale; the two modules are kept structurally -identical (sync method names drop the ``async``/``await`` keywords) so fixes/features land in -both at once. - -``websockets`` is required for this feature and is *not* a hard dependency of the package; it -is imported lazily so importing the SDK never fails when it is absent. +Use ``client.beta.voice_agents.realtime.connect(...)`` as a context manager. +Send text or audio through the connection and receive model events. +Install ``azure-ai-projects[voice]`` for the optional WebSocket dependencies. """ from __future__ import annotations @@ -24,6 +20,7 @@ from typing import ( Any, Dict, + Generic, Iterator, List, Mapping, @@ -31,6 +28,7 @@ Protocol, Tuple, Type, + TypeVar, TYPE_CHECKING, Union, cast, @@ -47,15 +45,10 @@ _LOGGER = logging.getLogger("azure.ai.projects.realtime") -# The realtime WebSocket route is voice-agent-specific (see `_to_ws_url`'s -# `/endpoint/protocols/voice` path), so this is always the correct opt-in value -- callers -# cannot and do not need to override it. +# Voice-agent WebSocket requests need the same preview header as REST requests. _VOICE_AGENT_FEATURE_HEADER: str = _AgentDefinitionOptInKeys.VOICE_AGENTS_V1_PREVIEW.value -# Identifies the SDK to the service on the WebSocket handshake, which otherwise falls back to -# the underlying `websockets` library's generic default (the generated HTTP surface gets this -# for free from the pipeline's own UserAgentPolicy; this hand-written client builds its own -# request instead, so it needs to opt in explicitly the same way). +# The WebSocket handshake does not use the HTTP pipeline, so identify the SDK explicitly. _USER_AGENT: str = UserAgentPolicy(sdk_moniker=f"ai-projects/{VERSION}").user_agent if TYPE_CHECKING: @@ -65,14 +58,7 @@ class _ConfigProvider(Protocol): - """Anything exposing the shared client configuration (endpoint, credential, etc.). - - :class:`~azure.ai.projects.operations.BetaVoiceAgentsOperations` (accessed as - ``client.beta.voice_agents``) satisfies this: it is constructed with the same shared - configuration instance as the top-level client, so ``client.beta.voice_agents.realtime`` can - reuse the endpoint/credential wiring without needing a back-reference to the top-level client - itself. - """ + """Provide the project endpoint, credential, and shared client settings.""" _config: "AIProjectClientConfiguration" @@ -147,6 +133,7 @@ class _ConfigProvider(Protocol): "input_audio_buffer.speech_started": _models.RealtimeServerEventInputAudioBufferSpeechStarted, "input_audio_buffer.speech_stopped": _models.RealtimeServerEventInputAudioBufferSpeechStopped, "input_audio_buffer.timeout_triggered": (_models.RealtimeServerEventInputAudioBufferTimeoutTriggered), + "input_collection.status": _models.VoiceAgentServerEventInputCollectionStatus, "mcp_list_tools.completed": _models.RealtimeServerEventMCPListToolsCompleted, "mcp_list_tools.failed": _models.RealtimeServerEventMCPListToolsFailed, "mcp_list_tools.in_progress": _models.RealtimeServerEventMCPListToolsInProgress, @@ -177,6 +164,8 @@ class _ConfigProvider(Protocol): "response.output_item.done": _models.RealtimeServerEventResponseOutputItemDone, "response.output_text.delta": _models.RealtimeServerEventResponseTextDelta, "response.output_text.done": _models.RealtimeServerEventResponseTextDone, + "response.system_tool_arguments.delta": _models.VoiceAgentServerEventSystemToolArgumentsDelta, + "response.system_tool_arguments.done": _models.VoiceAgentServerEventSystemToolArgumentsDone, "response.video.delta": _models.VoiceAgentServerEventResponseVideoDelta, "rtc.call.error": _models.VoiceAgentServerEventRtcCallError, "rtc.call.sdp.created": _models.VoiceAgentServerEventRtcCallSdpCreated, @@ -184,6 +173,9 @@ class _ConfigProvider(Protocol): "session.avatar.switch_to_idle": _models.VoiceAgentServerEventSessionAvatarSwitchToIdle, "session.avatar.switch_to_speaking": _models.VoiceAgentServerEventSessionAvatarSwitchToSpeaking, "session.created": _models.RealtimeServerEventSessionCreated, + "session.handoff.aborted": _models.VoiceAgentServerEventSessionHandoffAborted, + "session.handoff.completed": _models.VoiceAgentServerEventSessionHandoffCompleted, + "session.handoff.started": _models.VoiceAgentServerEventSessionHandoffStarted, "session.subagent.aborted": _models.VoiceAgentServerEventSessionSubagentAborted, "session.subagent.completed": _models.VoiceAgentServerEventSessionSubagentCompleted, "session.subagent.started": _models.VoiceAgentServerEventSessionSubagentStarted, @@ -210,6 +202,7 @@ class _ConfigProvider(Protocol): _models.RealtimeServerEventInputAudioBufferSpeechStarted, _models.RealtimeServerEventInputAudioBufferSpeechStopped, _models.RealtimeServerEventInputAudioBufferTimeoutTriggered, + _models.VoiceAgentServerEventInputCollectionStatus, _models.RealtimeServerEventMCPListToolsCompleted, _models.RealtimeServerEventMCPListToolsFailed, _models.RealtimeServerEventMCPListToolsInProgress, @@ -239,6 +232,8 @@ class _ConfigProvider(Protocol): _models.RealtimeServerEventResponseOutputItemDone, _models.RealtimeServerEventResponseTextDelta, _models.RealtimeServerEventResponseTextDone, + _models.VoiceAgentServerEventSystemToolArgumentsDelta, + _models.VoiceAgentServerEventSystemToolArgumentsDone, _models.VoiceAgentServerEventResponseVideoDelta, _models.VoiceAgentServerEventRtcCallError, _models.VoiceAgentServerEventRtcCallSdpCreated, @@ -246,6 +241,9 @@ class _ConfigProvider(Protocol): _models.VoiceAgentServerEventSessionAvatarSwitchToIdle, _models.VoiceAgentServerEventSessionAvatarSwitchToSpeaking, _models.RealtimeServerEventSessionCreated, + _models.VoiceAgentServerEventSessionHandoffAborted, + _models.VoiceAgentServerEventSessionHandoffCompleted, + _models.VoiceAgentServerEventSessionHandoffStarted, _models.VoiceAgentServerEventSessionSubagentAborted, _models.VoiceAgentServerEventSessionSubagentCompleted, _models.VoiceAgentServerEventSessionSubagentStarted, @@ -551,28 +549,22 @@ def cancel(self, *, response_id: Optional[str] = None, event_id: Optional[str] = ) -class BetaRealtimeConnection: # pylint: disable=too-many-instance-attributes - """An open realtime WebSocket connection to a voice agent. +_ServerEventT = TypeVar("_ServerEventT") +_ClientEventT = TypeVar("_ClientEventT") - Iterate over the connection to receive strongly-typed server events, and use the - sub-namespaces to send strongly-typed client events:: - with client.beta.voice_agents.realtime.connect(agent_name="my-agent") as conn: - for event in conn: - if event.type == RealtimeServerEventType.RESPONSE_DONE: - break - """ +class _BaseWebSocketConnection(Generic[_ServerEventT, _ClientEventT]): + """Shared synchronous WebSocket transport for the two voice protocols.""" + + _logger = _LOGGER + _server_event_types = _SERVER_EVENT_TYPES + _protocol_name = "realtime" def __init__(self, connection: "ClientConnection") -> None: self._connection = connection self._closed = False - self.session: SessionResource = SessionResource(self) - self.input_audio_buffer: InputAudioBufferResource = InputAudioBufferResource(self) - self.output_audio_buffer: OutputAudioBufferResource = OutputAudioBufferResource(self) - self.conversation: ConversationResource = ConversationResource(self) - self.response: ResponseResource = ResponseResource(self) - def __enter__(self) -> "BetaRealtimeConnection": + def __enter__(self) -> "_BaseWebSocketConnection[_ServerEventT, _ClientEventT]": return self def __exit__(self, *exc_details: Any) -> None: @@ -580,7 +572,7 @@ def __exit__(self, *exc_details: Any) -> None: def __repr__(self) -> str: state = "closed" if self.closed else "open" - return f"" + return f"<{type(self).__name__} [{state}]>" @property def closed(self) -> bool: @@ -590,76 +582,62 @@ def closed(self) -> bool: """ return self._closed - def __iter__(self) -> Iterator[ServerEvent]: + def __iter__(self) -> Iterator[_ServerEventT]: return self._iter() - def _iter(self) -> Iterator[ServerEvent]: + def _iter(self) -> Iterator[_ServerEventT]: while True: try: yield self.recv() except ConnectionResetError as exc: - # recv() below chains the *specific* websockets exception as the cause: a plain - # graceful closure has no cause (nothing went wrong), while an abnormal closure - # is chained from the ConnectionClosed that caused it. Only end iteration quietly - # for the former -- a `for event in conn:` caller must still see real failures - # (abnormal close codes, e.g. 1011) instead of silently observing end-of-stream. if exc.__cause__ is None: return raise - def recv(self, *, timeout: Optional[float] = None) -> ServerEvent: - """Receive and parse the next server event. - - Known event types are returned as their strongly-typed - ``VoiceAgentServerEventXxx`` model. Event types not (yet) represented by a - generated model are returned as a plain ``dict`` for forward compatibility. + def recv(self, *, timeout: Optional[float] = None) -> _ServerEventT: + """Receive a typed event, or a mapping for an unknown event. - :keyword timeout: Maximum time in seconds to wait for the next event. If ``None`` - (the default), block until an event is received. If no event arrives within - ``timeout`` seconds, raise :exc:`TimeoutError`. + :keyword timeout: Maximum receive wait in seconds; None waits indefinitely. :paramtype timeout: float or None - :return: The parsed server event. - :rtype: ~azure.ai.projects.ServerEvent - :raises ConnectionResetError: If the connection was closed by the server, gracefully or - otherwise. Iterating over the connection (``for event in conn:``) treats only a graceful - closure as end-of-stream and re-raises this for an abnormal one. - :raises TimeoutError: If ``timeout`` elapses before an event is received. + :return: The server event. + :rtype: object + :raises ConnectionResetError: On graceful or abnormal socket closure. + :raises TimeoutError: When the receive deadline expires. """ - from websockets.exceptions import ( # pylint: disable=import-outside-toplevel + from websockets.exceptions import ( ConnectionClosed, ConnectionClosedOK, - ) + ) # pylint: disable=import-outside-toplevel try: raw = self._connection.recv(timeout=timeout) except ConnectionClosedOK: self._closed = True - raise ConnectionResetError("The realtime connection was closed.") from None + raise ConnectionResetError(f"The {self._protocol_name} connection was closed.") from None except ConnectionClosed as exc: self._closed = True - raise ConnectionResetError(f"The realtime connection was closed abnormally: {exc}") from exc + raise ConnectionResetError(f"The {self._protocol_name} connection was closed abnormally: {exc}") from exc data = raw.decode("utf-8") if isinstance(raw, (bytes, bytearray)) else raw payload: Dict[str, Any] = json.loads(data) + if not isinstance(payload, dict): + raise ValueError("The WebSocket server event must be a JSON object.") event_type = payload.get("type") - _LOGGER.debug( + self._logger.debug( "WebSocket RECEIVE type=%s bytes=%d", event_type if isinstance(event_type, str) else "unknown", len(data.encode("utf-8")), ) - if not isinstance(event_type, str): - return payload - event_cls = _SERVER_EVENT_TYPES.get(event_type) - if event_cls is None: - return payload - return event_cls(payload) + event_cls = self._server_event_types.get(event_type) if isinstance(event_type, str) else None + return cast(_ServerEventT, event_cls(payload) if event_cls else payload) - def send(self, event: ClientEvent) -> None: - """Send a client event over the connection. + def send(self, event: _ClientEventT) -> None: + """Send a generated event, mapping, or JSON string. - :param event: A strongly-typed client event, a ready-made mapping, or a raw JSON string. - :type event: ~azure.ai.projects.ClientEvent or str - :raises ValueError: If ``event`` is a ``str`` that is not valid JSON. + :param event: The client event. + :type event: object + :raises ValueError: If the JSON string is invalid. """ + payload: str if isinstance(event, str): try: event_payload = json.loads(event) @@ -670,7 +648,7 @@ def send(self, event: ClientEvent) -> None: payload = json.dumps(event, cls=SdkJSONEncoder) event_payload = json.loads(payload) event_type = event_payload.get("type") if isinstance(event_payload, dict) else None - _LOGGER.debug( + self._logger.debug( "WebSocket SEND type=%s bytes=%d", event_type if isinstance(event_type, str) else "unknown", len(payload.encode("utf-8")), @@ -678,21 +656,106 @@ def send(self, event: ClientEvent) -> None: self._connection.send(payload) def close(self, *, code: int = 1000, reason: str = "") -> None: - """Close the connection. + """Close the socket once. - :keyword int code: The WebSocket close code. - :keyword str reason: The close reason. + :keyword int code: WebSocket close code. + :keyword str reason: WebSocket close reason. """ if self._closed: return - _LOGGER.debug("WebSocket CLOSE code=%d", code) + self._logger.debug("WebSocket CLOSE code=%d", code) try: self._connection.close(code=code, reason=reason) finally: self._closed = True -class BetaRealtimeConnectionManager: # pylint: disable=too-many-instance-attributes +class BetaRealtimeConnection( + _BaseWebSocketConnection[ServerEvent, ClientEvent] +): # pylint: disable=too-many-instance-attributes + """An open realtime WebSocket connection to a voice agent. + + Iterate to receive events. Use ``conversation``, ``response``, and the audio + buffers to send messages and control replies:: + + with client.beta.voice_agents.realtime.connect(agent_name="my-agent") as conn: + for event in conn: + if event.type == RealtimeServerEventType.RESPONSE_DONE: + break + """ + + def __init__(self, connection: "ClientConnection") -> None: + super().__init__(connection) + self.session: SessionResource = SessionResource(self) + self.input_audio_buffer: InputAudioBufferResource = InputAudioBufferResource(self) + self.output_audio_buffer: OutputAudioBufferResource = OutputAudioBufferResource(self) + self.conversation: ConversationResource = ConversationResource(self) + self.response: ResponseResource = ResponseResource(self) + + def __enter__(self) -> "BetaRealtimeConnection": + return self + + def __exit__(self, *exc_details: Any) -> None: + self.close() + + @property + def closed(self) -> bool: + """Whether the underlying WebSocket connection has been closed. + + :rtype: bool + """ + return self._closed + + def __iter__(self) -> Iterator[ServerEvent]: + return self._iter() + + def _iter(self) -> Iterator[ServerEvent]: + while True: + try: + yield self.recv() + except ConnectionResetError as exc: + # recv() below chains the *specific* websockets exception as the cause: a plain + # graceful closure has no cause (nothing went wrong), while an abnormal closure + # is chained from the ConnectionClosed that caused it. Only end iteration quietly + # for the former -- a `for event in conn:` caller must still see real failures + # (abnormal close codes, e.g. 1011) instead of silently observing end-of-stream. + if exc.__cause__ is None: + return + raise + + def recv(self, *, timeout: Optional[float] = None) -> ServerEvent: + """Receive and parse the next server event. + + Known events use SDK model classes. Unknown event types are returned + as dictionaries. + + :keyword timeout: Maximum time in seconds to wait for the next event. If ``None`` + (the default), block until an event is received. If no event arrives within + ``timeout`` seconds, raise :exc:`TimeoutError`. + :paramtype timeout: float or None + :return: The parsed server event. + :rtype: ~azure.ai.projects.ServerEvent + :raises ConnectionResetError: If the connection was closed by the server, gracefully or + otherwise. Iterating over the connection (``for event in conn:``) treats only a graceful + closure as end-of-stream and re-raises this for an abnormal one. + :raises TimeoutError: If ``timeout`` elapses before an event is received. + """ + return super().recv(timeout=timeout) + + def send(self, event: ClientEvent) -> None: + """Send a client event over the connection. + + :param event: A client event model, mapping, or JSON string. + :type event: ~azure.ai.projects.ClientEvent or str + :raises ValueError: If ``event`` is a ``str`` that is not valid JSON. + """ + super().send(event) + + +_ConnectionT = TypeVar("_ConnectionT", bound=_BaseWebSocketConnection) + + +class _BaseWebSocketConnectionManager(Generic[_ConnectionT]): # pylint: disable=too-many-instance-attributes """Context manager that opens a :class:`BetaRealtimeConnection`. Returned by :meth:`BetaRealtime.connect`; you normally use it as @@ -747,12 +810,16 @@ def __init__( # pylint: disable=too-many-arguments self._extra_query = dict(extra_query or {}) self._extra_headers = dict(extra_headers or {}) self._kwargs = kwargs - self._connection: Optional[BetaRealtimeConnection] = None + self._connection: Optional[_ConnectionT] = None - def __enter__(self) -> BetaRealtimeConnection: + _logger = _LOGGER + _subprotocol: Optional[str] = "realtime" + _protocol_name = "realtime" + + def __enter__(self) -> _ConnectionT: return self.enter() - def enter(self) -> BetaRealtimeConnection: # pylint: disable=too-many-locals + def enter(self) -> _ConnectionT: # pylint: disable=too-many-locals """Open the connection. :return: The live realtime connection. @@ -767,41 +834,30 @@ def enter(self) -> BetaRealtimeConnection: # pylint: disable=too-many-locals from websockets.typing import Subprotocol # pylint: disable=import-outside-toplevel except ImportError as exc: # pragma: no cover - dependency guard raise RuntimeError( - "The realtime client requires `websockets`. Install it with `pip install websockets`." + f"The {self._protocol_name} client requires `websockets`. Install it with `pip install websockets`." ) from exc # ``connection_url`` fully overrides the computed route (scheme/host/path). This is the # escape hatch used to reach a specific data-plane host/path directly. if self._connection_url is not None: _assert_trusted_connection_url(self._connection_url, self._endpoint) - url = self._connection_url or _to_ws_url(self._endpoint, self._agent_name) + url = self._connection_url or self._get_url() if self._transport is not None: url = _without_transport_query(url) if not url.startswith("wss://"): - raise ValueError("The realtime WebSocket URL must use wss:// to protect credentials in transit.") - - params: Dict[str, str] = {"api-version": self._api_version, "x-ms-client-sdk": _USER_AGENT} - if self._agent_session_id is not None: - params["agent_session_id"] = self._agent_session_id - if self._structured_inputs is not None: - # The service reads this from the `structured_input` query parameter (see the - # generated `build_beta_voice_agents_realtime_connect_voice_agent_request`), not a - # header -- it must be serialized and appended to the URL below, not sent as one. - params["structured_input"] = json.dumps(self._structured_inputs, cls=SdkJSONEncoder) - params.update(self._extra_query) - if self._transport is not None: - params["transport"] = self._transport + raise ValueError( + f"The {self._protocol_name} WebSocket URL must use wss:// to protect credentials in transit." + ) + params = self._get_query() if params: - # Preserve an existing query string on a `connection_url` override (for example a - # SAS-style `?sig=...`) instead of unconditionally appending a second `?`. delimiter = "&" if urlparse(url).query else "?" full_url = f"{url}{delimiter}{urlencode(params)}" else: full_url = url target_url = urlparse(url)._replace(query="", fragment="").geturl() - _LOGGER.debug("WebSocket CONNECT target=%s", target_url) + self._logger.debug("WebSocket CONNECT target=%s", target_url) token = self._credential.get_token(*self._credential_scopes) headers: Dict[str, str] = { @@ -810,27 +866,15 @@ def enter(self) -> BetaRealtimeConnection: # pylint: disable=too-many-locals } headers.update(self._extra_headers) if not _has_header_case_insensitive(headers, "User-Agent"): - # Only set our default if the caller didn't supply their own (in any casing) -- - # a plain dict merge would otherwise leave both as separate keys (HTTP header names - # are case-insensitive, but Python dict keys are not), sending two User-Agent-like - # headers instead of cleanly honoring the caller's override. headers["User-Agent"] = _USER_AGENT try: - # Force the "realtime" WebSocket subprotocol regardless of any caller-supplied - # override in ``self._kwargs``: the service requires this exact subprotocol, so - # silently accepting a different one here would just move the failure to a less - # clear error inside the handshake. Also disable ``websockets``' own - # ``user_agent_header`` default: unlike aiohttp, it is a wholly separate mechanism - # from ``additional_headers`` -- passing our own "User-Agent" there does not - # override it, so without this the connection would carry two distinct - # User-Agent-like values. ws_connect_kwargs = dict(self._kwargs) ws_connect_kwargs.pop("subprotocols", None) connection = _ws_connect( full_url, additional_headers=headers, - subprotocols=[Subprotocol("realtime")], + subprotocols=[Subprotocol(self._subprotocol)] if self._subprotocol else None, user_agent_header=None, **ws_connect_kwargs, ) @@ -838,24 +882,59 @@ def enter(self) -> BetaRealtimeConnection: # pylint: disable=too-many-locals if not isinstance(exc, Exception) or isinstance(exc, (ValueError, RuntimeError)): raise raise ConnectionError( - f"Failed to open the realtime WebSocket connection to voice agent " + f"Failed to open the {self._protocol_name} WebSocket connection to voice agent " f"'{self._agent_name}' at '{url}': {exc}" ) from exc - _LOGGER.debug("WebSocket CONNECTED target=%s", target_url) - self._connection = BetaRealtimeConnection(connection) + self._logger.debug("WebSocket CONNECTED target=%s", target_url) + self._connection = self._create_connection(connection) return self._connection + def _get_url(self) -> str: + return _to_ws_url(self._endpoint, self._agent_name) + + def _get_query(self) -> Dict[str, str]: + params: Dict[str, str] = {"api-version": self._api_version, "x-ms-client-sdk": _USER_AGENT} + if self._agent_session_id is not None: + params["agent_session_id"] = self._agent_session_id + if self._structured_inputs is not None: + params["structured_inputs"] = json.dumps(self._structured_inputs, cls=SdkJSONEncoder) + params.update(self._extra_query) + if self._transport is not None: + params["transport"] = self._transport + + return params + + def _create_connection(self, connection: "ClientConnection") -> _ConnectionT: + raise NotImplementedError + def __exit__(self, *exc_details: Any) -> None: if self._connection is not None: self._connection.close() self._connection = None +class BetaRealtimeConnectionManager(_BaseWebSocketConnectionManager[BetaRealtimeConnection]): + """Context manager for a synchronous Realtime connection.""" + + def __enter__(self) -> BetaRealtimeConnection: + return self.enter() + + def enter(self) -> BetaRealtimeConnection: + """Open the Realtime connection. + + :return: The Realtime connection. + :rtype: ~azure.ai.projects.operations.BetaRealtimeConnection + """ + return super().enter() + + def _create_connection(self, connection: "ClientConnection") -> BetaRealtimeConnection: + return BetaRealtimeConnection(connection) + + class BetaRealtime: # pylint: disable=too-few-public-methods - """BetaRealtime streaming entry point, exposed as ``client.beta.voice_agents.realtime``. + """Connect to a voice agent through ``client.beta.voice_agents.realtime``. - Follows the OpenAI Python realtime surface: obtain it from the HTTP client and open a - connection with :meth:`connect`:: + Open a connection with :meth:`connect`:: from azure.ai.projects import AIProjectClient from azure.identity import DefaultAzureCredential @@ -869,9 +948,7 @@ class BetaRealtime: # pylint: disable=too-few-public-methods if event.type == RealtimeServerEventType.RESPONSE_DONE: break - :param client: The object whose endpoint and credential are reused for the realtime - handshake -- the ``.beta.voice_agents`` sub-client, which shares the same underlying - configuration as the top-level client. + :param client: The voice-agent client that supplies the project endpoint and credential. :type client: ~azure.ai.projects.operations.BetaVoiceAgentsOperations """ @@ -900,16 +977,11 @@ def connect( # pylint: disable=too-many-arguments :keyword agent_session_id: An optional identifier used to correlate the voice session. Default value is None. :paramtype agent_session_id: str or None - :keyword transport: The transport used for this connection. Known values are - ``VoiceAgentTransport.WEBSOCKET`` and ``VoiceAgentTransport.WEBRTC``. When omitted, the - service defaults to WebSocket. The SDK constructs the wire query internally; an explicit - selection overrides an existing transport query value. For WebRTC, the caller must - manage the peer connection, media, and SDP offer/answer exchange. + :keyword transport: ``VoiceAgentTransport.WEBSOCKET`` (service default) or + ``VoiceAgentTransport.WEBRTC``. An explicit value overrides ``extra_query``. + WebRTC requires your app to handle the peer connection, media, and SDP exchange. :paramtype transport: str or ~azure.ai.projects.models.VoiceAgentTransport or None - :keyword structured_inputs: A mapping of structured-input names to their values for this - session (see :attr:`~azure.ai.projects.models.CreateTelephonyCallJobRequest.structured_inputs` - for the analogous shape used elsewhere). Serialized to JSON on the wire. Default value is - None. + :keyword structured_inputs: Values for the agent's structured-input placeholders. :paramtype structured_inputs: Mapping[str, Any] or None :keyword connection_url: Full ``wss://`` URL that overrides the route computed from the client endpoint. Query parameters are still appended. Default value is None. diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_unions.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_unions.py index 73da9e2b48ee..459fb4b4c6c8 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_unions.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_unions.py @@ -15,7 +15,20 @@ Literal["none"], Literal["auto"], Literal["required"], "_models.ToolChoiceFunction", "_models.ToolChoiceMCP" ] VoiceAgentMaxOutputTokens: TypeAlias = Union[int, Literal["inf"]] +VoiceAgentHandoffMaxOutputTokens: TypeAlias = Union[int, Literal["inf"]] RoutineRunStatus: TypeAlias = str -VoiceAgentSessionUpdate: TypeAlias = "_models.VoiceAgentSessionUpdateConfig" VoiceAgentSessionResponse: TypeAlias = "_models.VoiceAgentSessionResponseConfig" +RealtimeResponseInputItem: TypeAlias = Union[ + "_models.RealtimeResponseInputMessage", + "_models.RealtimeResponseInputFunctionCall", + "_models.RealtimeResponseInputFunctionCallOutput", + "_models.RealtimeResponseItemReference", +] +VoiceAgentSessionUpdate: TypeAlias = "_models.VoiceAgentSessionUpdateConfig" +VoiceAgentDtmfCompletionMode: TypeAlias = Union[ + "_models.VoiceAgentDtmfFixedLengthCompletionMode", + "_models.VoiceAgentDtmfTerminatorCompletionMode", + "_models.VoiceAgentDtmfInterDigitSilenceCompletionMode", +] +ChoiceValueResource: TypeAlias = Union[str, bool] GenerateAgentRequest: TypeAlias = "_models.GenerateVoiceAgentRequest" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/campaign_polling.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/campaign_polling.py new file mode 100644 index 000000000000..17b692e19d39 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/campaign_polling.py @@ -0,0 +1,106 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Polling customizations for Voice Agent campaigns. + +The pinned campaign-routes.tsp at 3e2177ff982e0e0af47a19f1bed59187f9084929 +declares a final GET guarded by the initiating Operation-Id. The emitted +methods use default Azure Core routing instead. The generation-commit +configuration pins typespec-python 0.63.10 and http-client-python 0.39.0, +but the resolved emission log is unavailable; the emitter-side cause remains +unverified. Follow up upstream with these inputs and remove this routing +workaround when regenerated methods pass the campaign LRO regression tests. +""" + +from collections.abc import Mapping +from typing import Any, Optional +from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit + +from azure.core.pipeline import PipelineResponse +from azure.core.polling.base_polling import ( + BadResponse, + LocationPolling, + OperationResourcePolling, + StatusCheckPolling, +) +from azure.core.rest import HttpRequest, HttpResponse +from azure.core.utils import case_insensitive_dict + +from .polling import AIProjectsLROBasePolling, AsyncAIProjectsLROBasePolling + + +class _CampaignOperationResourcePolling(OperationResourcePolling[HttpRequest, HttpResponse]): + def __init__(self, *, lro_options: Optional[dict[str, Any]] = None) -> None: + super().__init__(lro_options=lro_options) + self._operation_id: Optional[str] = None + + def set_initial_status(self, pipeline_response: PipelineResponse[HttpRequest, HttpResponse]) -> str: + self._operation_id = case_insensitive_dict(pipeline_response.http_response.headers).get("Operation-Id") + return super().set_initial_status(pipeline_response) + + def get_final_get_url(self, pipeline_response: PipelineResponse[HttpRequest, HttpResponse]) -> Optional[str]: + if self._request.method == "DELETE": + return None + if self._request.method not in {"PUT", "POST"}: + return super().get_final_get_url(pipeline_response) + if not self._operation_id: + raise BadResponse("Campaign operation response is missing Operation-Id; cannot guard the final GET.") + + url = urlsplit(self._request.url) + path = url.path + if self._request.method == "POST": + if not path.endswith(":cancel"): + raise BadResponse("Campaign cancellation request URL must end with ':cancel'.") + path = path.removesuffix(":cancel") + query = [(key, value) for key, value in parse_qsl(url.query, keep_blank_values=True) if key != "operation_id"] + query.append(("operation_id", self._operation_id)) + return urlunsplit(url._replace(path=path, query=urlencode(query))) + + +class _CampaignLROBasePolling(AIProjectsLROBasePolling): + def _filter_headers_for_continuation_token(self, headers: Mapping[str, str]) -> dict[str, str]: + filtered = super()._filter_headers_for_continuation_token(headers) + operation_id = case_insensitive_dict(headers).get("Operation-Id") + if operation_id is not None: + filtered["Operation-Id"] = operation_id + return filtered + + +class _AsyncCampaignLROBasePolling(AsyncAIProjectsLROBasePolling): + def _filter_headers_for_continuation_token(self, headers: Mapping[str, str]) -> dict[str, str]: + filtered = super()._filter_headers_for_continuation_token(headers) + operation_id = case_insensitive_dict(headers).get("Operation-Id") + if operation_id is not None: + filtered["Operation-Id"] = operation_id + return filtered + + +def _configure_campaign_polling( + kwargs: dict[str, Any], + polling_interval: float, + path_format_arguments: dict[str, str], + *, + is_async: bool = False, +) -> None: + if kwargs.get("polling", True) is not True: + return + + polling_kwargs = { + key: value + for key, value in kwargs.items() + if key + not in {"cls", "content_type", "continuation_token", "error_map", "params", "polling", "polling_interval"} + } + if not polling_kwargs.get("lro_algorithms"): + polling_kwargs["lro_algorithms"] = [ + _CampaignOperationResourcePolling(lro_options=polling_kwargs.get("lro_options")), + LocationPolling(), + StatusCheckPolling(), + ] + polling_type = _AsyncCampaignLROBasePolling if is_async else _CampaignLROBasePolling + kwargs["polling"] = polling_type( + kwargs.get("polling_interval", polling_interval), + path_format_arguments=path_format_arguments, + **polling_kwargs, + ) 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 8dbc8389f5a3..ac7336e65dd8 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.10.0" +VERSION = "2.11.0" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_live.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_live.py new file mode 100644 index 000000000000..d32aa437af9b --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_live.py @@ -0,0 +1,330 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------- +"""Asynchronous GPT Live sessions at ``client.beta.voice_agents.live``.""" + +from __future__ import annotations + +import base64 +from typing import Any, AsyncIterator, Mapping, Optional, TYPE_CHECKING, Union + +from .. import models +from .._live_utils import LiveClientEvent, LiveServerEvent, _LOGGER, _SERVER_EVENT_TYPES, _event, _live_query, _live_url +from ._realtime import _BaseWebSocketConnection, _BaseWebSocketConnectionManager, _ConfigProvider + +if TYPE_CHECKING: + from aiohttp import ( # pylint: disable=networking-import-outside-azure-core-transport + ClientSession, + ClientWebSocketResponse, + ) + +__all__ = [ + "AsyncBetaLive", + "AsyncBetaLiveConnection", + "AsyncBetaLiveConnectionManager", + "LiveClientEvent", + "LiveServerEvent", +] + + +class _Resource: + def __init__(self, connection: AsyncBetaLiveConnection) -> None: + self._connection = connection + + +class TextResource(_Resource): + """Send instructions, unspoken context, or spoken commentary. + + :param connection: The parent Live connection. + :type connection: ~azure.ai.projects.aio.operations.AsyncBetaLiveConnection + :param event_model: The generated model for the text command. + :type event_model: type[~azure.ai.projects.models.LiveClientEvent] + """ + + def __init__(self, connection: AsyncBetaLiveConnection, event_model: type[models.LiveClientEvent]) -> None: + super().__init__(connection) + self._event_model = event_model + + async def append(self, *, content: str, delegation_id: Optional[str], event_id: Optional[str] = None) -> None: + """Send text, optionally tied to a request delegated to your app. + + :keyword str content: Text to append. + :keyword delegation_id: The delegated request's ID, or None for standalone text. + :paramtype delegation_id: str or None + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send(_event(self._event_model, event_id, content=content, delegation_id=delegation_id)) + + +class InputAudioResource(_Resource): + """Send audio using the session's configured format.""" + + async def append(self, *, audio: Union[str, bytes], event_id: Optional[str] = None) -> None: + """Send raw audio bytes or base64 without a container header. + + :keyword audio: Raw audio or an already base64-encoded string. + :paramtype audio: str or bytes + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + encoded = base64.b64encode(audio).decode("ascii") if isinstance(audio, bytes) else audio + await self._connection.send(_event(models.LiveClientEventLiveInputAudioAppendEvent, event_id, audio=encoded)) + + async def mute(self, *, event_id: Optional[str] = None) -> None: + """Mute input audio processing. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send(_event(models.LiveClientEventLiveInputAudioMuteParam, event_id)) + + async def unmute(self, *, event_id: Optional[str] = None) -> None: + """Resume input audio processing. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send(_event(models.LiveClientEventLiveInputAudioUnmuteParam, event_id)) + + +class SessionResource(_Resource): + """Control a Live session that Foundry starts when the connection opens. + + :param connection: The parent Live connection. + :type connection: ~azure.ai.projects.aio.operations.AsyncBetaLiveConnection + """ + + def __init__(self, connection: AsyncBetaLiveConnection) -> None: + super().__init__(connection) + self.input_audio = InputAudioResource(connection) + self.instructions = TextResource(connection, models.LiveClientEventLiveInstructionsAppendParam) + self.thinking = TextResource(connection, models.LiveClientEventLiveThinkingAppendParam) + self.commentary = TextResource(connection, models.LiveClientEventLiveCommentaryAppendParam) + + async def update( + self, *, session: Union[models.LiveSessionUpdateParams, Mapping[str, Any]], event_id: Optional[str] = None + ) -> None: + """Update backend delegation settings or transcript triggers. + + The persisted Foundry delegation target, frontend model, and audio format cannot change + mid-session. + + :keyword session: The backend settings or transcript triggers to change. + :paramtype session: ~azure.ai.projects.models.LiveSessionUpdateParams or Mapping[str, Any] + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send(_event(models.LiveClientEventLiveSessionUpdateParam, event_id, session=session)) + + async def close(self, *, event_id: Optional[str] = None) -> None: + """Request graceful session shutdown; receive session.closed before closing the socket. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send(_event(models.LiveClientEventLiveSessionCloseParam, event_id)) + + +class ResponseItemResource(_Resource): + """Send user messages or tool results to the Responses backend model.""" + + async def create(self, *, item: Mapping[str, Any], event_id: Optional[str] = None) -> None: + """Send a message or tool result. Requires a Responses backend. + + :keyword item: Responses input item, including function_call_output. + :paramtype item: Mapping[str, Any] + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send( + _event(models.LiveClientEventLiveResponseItemCreateParam, event_id, item=dict(item)) + ) + + +class ResponseResource(_Resource): + """Request replies from the Responses backend model. + + :param connection: The parent Live connection. + :type connection: ~azure.ai.projects.aio.operations.AsyncBetaLiveConnection + """ + + def __init__(self, connection: AsyncBetaLiveConnection) -> None: + super().__init__(connection) + self.item = ResponseItemResource(connection) + + async def create(self, *, event_id: Optional[str] = None) -> None: + """Request or continue a backend response after submitting tool results. + + :keyword event_id: Optional client event identifier. + :paramtype event_id: str or None + """ + await self._connection.send(_event(models.LiveClientEventLiveResponseCreateParam, event_id)) + + +class AsyncBetaLiveConnection(_BaseWebSocketConnection[LiveServerEvent, LiveClientEvent]): + """Send and receive events on a GPT Live connection. + + Service errors arrive as error events. Use the context manager to close + the connection. Send ``session.close`` to end the session; Live has no + ``response.cancel`` command. + + :param connection: The open WebSocket. + :type connection: ~aiohttp.ClientWebSocketResponse + :param session: The HTTP session that owns the WebSocket. + :type session: ~aiohttp.ClientSession + """ + + _logger = _LOGGER + _server_event_types = _SERVER_EVENT_TYPES + _protocol_name = "Live" + + def __init__(self, connection: ClientWebSocketResponse, session: ClientSession) -> None: + super().__init__(connection, session) + self.session = SessionResource(self) + self.response = ResponseResource(self) + + async def __aenter__(self) -> AsyncBetaLiveConnection: + return self + + def __aiter__(self) -> AsyncIterator[LiveServerEvent]: + return super().__aiter__() + + async def recv(self) -> LiveServerEvent: + """Receive an SDK event model, or a dictionary for an unknown event type. + + :return: The server event. + :rtype: ~azure.ai.projects.aio.operations.LiveServerEvent + :raises ConnectionResetError: On graceful or abnormal socket closure. + :raises ValueError: If the server event is not a JSON object. + """ + return await super().recv() + + async def send(self, event: LiveClientEvent) -> None: + """Send an SDK event model, mapping, or JSON string. + + :param event: The client event. + :type event: ~azure.ai.projects.aio.operations.LiveClientEvent + :raises ValueError: If the supplied JSON string is invalid. + """ + await super().send(dict(event) if isinstance(event, Mapping) else event) + + +class AsyncBetaLiveConnectionManager(_BaseWebSocketConnectionManager[AsyncBetaLiveConnection]): + """Context manager for one Live session using the project's credential. + + :keyword agent_version: A specific agent version, if needed. + :paramtype agent_version: str or None + :keyword store: Save conversation content and audio. None uses the agent's setting. + :paramtype store: bool or None + """ + + _logger = _LOGGER + _subprotocol = None + _protocol_name = "Live" + + def __init__( + self, + *, + agent_version: Optional[str] = None, + store: Optional[bool] = None, + **kwargs: Any, + ) -> None: + super().__init__(**kwargs) + self._agent_version = agent_version + self._store = store + + async def __aenter__(self) -> AsyncBetaLiveConnection: + return await self.enter() + + async def enter(self) -> AsyncBetaLiveConnection: + """Open the connection. Foundry starts the Live session automatically. + + :return: The Live connection. + :rtype: ~azure.ai.projects.aio.operations.AsyncBetaLiveConnection + :raises RuntimeError: If ``aiohttp`` is not installed. + :raises ValueError: If the computed or supplied WebSocket URL does not use ``wss://``. + :raises ConnectionError: If the WebSocket upgrade handshake fails. + """ + return await super().enter() + + def _get_url(self) -> str: + return _live_url(self._endpoint, self._agent_name) + + def _get_query(self) -> dict[str, str]: + return _live_query( + self._api_version, self._agent_version, self._structured_inputs, self._store, self._extra_query + ) + + def _create_connection( + self, connection: ClientWebSocketResponse, session: ClientSession + ) -> AsyncBetaLiveConnection: + return AsyncBetaLiveConnection(connection, session) + + +class AsyncBetaLive: + """Connect to GPT Live through ``client.beta.voice_agents.live``. + + Foundry starts the session from the saved agent settings. Wait for + ``session.started`` before sending commands; do not send ``session.start``. + + :param args: The voice-agent sub-client whose shared configuration is reused. + :type args: ~azure.ai.projects.aio.operations.BetaVoiceAgentsOperations + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + input_args = list(args) + client: _ConfigProvider = input_args.pop(0) if input_args else kwargs.pop("client") + self._config = client._config # pylint: disable=protected-access + + def connect( + self, + *, + agent_name: str, + agent_version: Optional[str] = None, + structured_inputs: Optional[Mapping[str, Any]] = None, + store: Optional[bool] = None, + connection_url: Optional[str] = None, + api_version: Optional[str] = None, + credential_scopes: Optional[list[str]] = None, + extra_query: Optional[Mapping[str, str]] = None, + extra_headers: Optional[Mapping[str, str]] = None, + **kwargs: Any, + ) -> AsyncBetaLiveConnectionManager: + """Connect to a GPT Live agent when entering the context manager. + + :keyword str agent_name: The name of an existing GPT Live agent. + :keyword agent_version: A specific agent version, if needed. + :paramtype agent_version: str or None + :keyword structured_inputs: Values for placeholders in the agent's instructions and greeting. + :paramtype structured_inputs: Mapping[str, Any] or None + :keyword store: Save conversation content and audio. None uses the agent's setting. + :paramtype store: bool or None + :keyword connection_url: A wss URL on the project endpoint's origin, instead of the default route. + :paramtype connection_url: str or None + :keyword api_version: API version override. + :paramtype api_version: str or None + :keyword credential_scopes: Token scope override. + :paramtype credential_scopes: list[str] or None + :keyword extra_query: Additional handshake query values. + :paramtype extra_query: Mapping[str, str] or None + :keyword extra_headers: Additional handshake headers. + :paramtype extra_headers: Mapping[str, str] or None + :return: An asynchronous Live connection context manager. + :rtype: ~azure.ai.projects.aio.operations.AsyncBetaLiveConnectionManager + """ + return AsyncBetaLiveConnectionManager( + endpoint=self._config.endpoint, + credential=self._config.credential, + credential_scopes=credential_scopes or self._config.credential_scopes, + api_version=api_version or self._config.api_version, + agent_name=agent_name, + agent_version=agent_version, + structured_inputs=structured_inputs, + store=store, + connection_url=connection_url, + extra_query=extra_query, + extra_headers=extra_headers, + **kwargs, + ) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py index 67ffc9df304c..32cd43b7139a 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py @@ -1,36 +1,20 @@ -# pylint: disable=networking-import-outside-azure-core-transport +# pylint: disable=networking-import-outside-azure-core-transport,too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------- -"""Hand-written async realtime (WebSocket) streaming client for voice agents. +"""Asynchronous Realtime voice-agent client. -BetaRealtime uses a fundamentally different transport (a persistent WebSocket) than the -request/response HTTP surface generated from the service's TypeSpec definition, so it is -hand-written and exposed as the ``AIProjectClient.beta.voice_agents.realtime`` namespace. - -The connection ergonomics follow the OpenAI Python realtime client so that developers moving -between the libraries get a familiar surface: - -* :meth:`AsyncBetaRealtime.connect` returns an async context manager. -* Entering the context yields an :class:`AsyncBetaRealtimeConnection`. -* The connection is async-iterable over inbound, strongly-typed server events and exposes - sub-namespaces (``session``, ``input_audio_buffer``, ``output_audio_buffer``, - ``conversation``, ``response``) for sending strongly-typed outbound client events. - -Outbound and inbound events use the generated ``VoiceAgentClientEventXxx``/ -``VoiceAgentServerEventXxx`` models directly where one exists. ``send`` and ``recv`` still -accept/return plain ``dict`` objects as a forward-compatible fallback for any event ``type`` -the generated models don't yet know about (for example ``conversation.created``, which is a -valid event but does not (yet) have a dedicated generated model in this package). - -``aiohttp`` is required for this feature and is *not* a hard dependency of the package; it is -imported lazily so importing the SDK never fails when it is absent. +Use ``async with client.beta.voice_agents.realtime.connect(...)`` to open a session. +Send text or audio through the connection and use ``async for`` to receive events. +Known events use SDK models; unknown event types are returned as dictionaries. +Install ``azure-ai-projects[voice]`` for the optional WebSocket dependencies. """ from __future__ import annotations +import asyncio # pylint: disable=do-not-import-asyncio import base64 import json import logging @@ -40,12 +24,14 @@ AsyncIterator, cast, Dict, + Generic, List, Mapping, Optional, Protocol, Tuple, Type, + TypeVar, TYPE_CHECKING, Union, ) @@ -61,15 +47,10 @@ _LOGGER = logging.getLogger("azure.ai.projects.realtime") -# The realtime WebSocket route is voice-agent-specific (see `_to_ws_url`'s -# `/endpoint/protocols/voice` path), so this is always the correct opt-in value -- callers -# cannot and do not need to override it. +# Voice-agent WebSocket requests need the same preview header as REST requests. _VOICE_AGENT_FEATURE_HEADER: str = _AgentDefinitionOptInKeys.VOICE_AGENTS_V1_PREVIEW.value -# Identifies the SDK to the service on the WebSocket handshake, which otherwise falls back to -# the underlying `aiohttp` library's generic default (the generated HTTP surface gets this for -# free from the pipeline's own UserAgentPolicy; this hand-written client builds its own request -# instead, so it needs to opt in explicitly the same way). +# The WebSocket handshake does not use the HTTP pipeline, so identify the SDK explicitly. _USER_AGENT: str = UserAgentPolicy(sdk_moniker=f"ai-projects/{VERSION}").user_agent if TYPE_CHECKING: @@ -79,14 +60,7 @@ class _ConfigProvider(Protocol): - """Anything exposing the shared client configuration (endpoint, credential, etc.). - - :class:`~azure.ai.projects.aio.operations.BetaVoiceAgentsOperations` (accessed as - ``async_client.beta.voice_agents``) satisfies this: it is constructed with the same shared - configuration instance as the top-level client, so ``async_client.beta.voice_agents.realtime`` - can reuse the endpoint/credential wiring without needing a back-reference to the top-level - client itself. - """ + """Provide the project endpoint, credential, and shared client settings.""" _config: "AIProjectClientConfiguration" @@ -161,6 +135,7 @@ class _ConfigProvider(Protocol): "input_audio_buffer.speech_started": _models.RealtimeServerEventInputAudioBufferSpeechStarted, "input_audio_buffer.speech_stopped": _models.RealtimeServerEventInputAudioBufferSpeechStopped, "input_audio_buffer.timeout_triggered": (_models.RealtimeServerEventInputAudioBufferTimeoutTriggered), + "input_collection.status": _models.VoiceAgentServerEventInputCollectionStatus, "mcp_list_tools.completed": _models.RealtimeServerEventMCPListToolsCompleted, "mcp_list_tools.failed": _models.RealtimeServerEventMCPListToolsFailed, "mcp_list_tools.in_progress": _models.RealtimeServerEventMCPListToolsInProgress, @@ -191,6 +166,8 @@ class _ConfigProvider(Protocol): "response.output_item.done": _models.RealtimeServerEventResponseOutputItemDone, "response.output_text.delta": _models.RealtimeServerEventResponseTextDelta, "response.output_text.done": _models.RealtimeServerEventResponseTextDone, + "response.system_tool_arguments.delta": _models.VoiceAgentServerEventSystemToolArgumentsDelta, + "response.system_tool_arguments.done": _models.VoiceAgentServerEventSystemToolArgumentsDone, "response.video.delta": _models.VoiceAgentServerEventResponseVideoDelta, "rtc.call.error": _models.VoiceAgentServerEventRtcCallError, "rtc.call.sdp.created": _models.VoiceAgentServerEventRtcCallSdpCreated, @@ -198,6 +175,9 @@ class _ConfigProvider(Protocol): "session.avatar.switch_to_idle": _models.VoiceAgentServerEventSessionAvatarSwitchToIdle, "session.avatar.switch_to_speaking": _models.VoiceAgentServerEventSessionAvatarSwitchToSpeaking, "session.created": _models.RealtimeServerEventSessionCreated, + "session.handoff.aborted": _models.VoiceAgentServerEventSessionHandoffAborted, + "session.handoff.completed": _models.VoiceAgentServerEventSessionHandoffCompleted, + "session.handoff.started": _models.VoiceAgentServerEventSessionHandoffStarted, "session.subagent.aborted": _models.VoiceAgentServerEventSessionSubagentAborted, "session.subagent.completed": _models.VoiceAgentServerEventSessionSubagentCompleted, "session.subagent.started": _models.VoiceAgentServerEventSessionSubagentStarted, @@ -224,6 +204,7 @@ class _ConfigProvider(Protocol): _models.RealtimeServerEventInputAudioBufferSpeechStarted, _models.RealtimeServerEventInputAudioBufferSpeechStopped, _models.RealtimeServerEventInputAudioBufferTimeoutTriggered, + _models.VoiceAgentServerEventInputCollectionStatus, _models.RealtimeServerEventMCPListToolsCompleted, _models.RealtimeServerEventMCPListToolsFailed, _models.RealtimeServerEventMCPListToolsInProgress, @@ -253,6 +234,8 @@ class _ConfigProvider(Protocol): _models.RealtimeServerEventResponseOutputItemDone, _models.RealtimeServerEventResponseTextDelta, _models.RealtimeServerEventResponseTextDone, + _models.VoiceAgentServerEventSystemToolArgumentsDelta, + _models.VoiceAgentServerEventSystemToolArgumentsDone, _models.VoiceAgentServerEventResponseVideoDelta, _models.VoiceAgentServerEventRtcCallError, _models.VoiceAgentServerEventRtcCallSdpCreated, @@ -260,6 +243,9 @@ class _ConfigProvider(Protocol): _models.VoiceAgentServerEventSessionAvatarSwitchToIdle, _models.VoiceAgentServerEventSessionAvatarSwitchToSpeaking, _models.RealtimeServerEventSessionCreated, + _models.VoiceAgentServerEventSessionHandoffAborted, + _models.VoiceAgentServerEventSessionHandoffCompleted, + _models.VoiceAgentServerEventSessionHandoffStarted, _models.VoiceAgentServerEventSessionSubagentAborted, _models.VoiceAgentServerEventSessionSubagentCompleted, _models.VoiceAgentServerEventSessionSubagentStarted, @@ -573,31 +559,29 @@ class _AbnormalWebSocketClosure(Exception): from a normal end of stream, which chains no cause.""" -class AsyncBetaRealtimeConnection: # pylint: disable=too-many-instance-attributes - """An open realtime WebSocket connection to a voice agent. +_ServerEventT = TypeVar("_ServerEventT", bound=Union[_Model, Mapping[str, Any]]) +_ClientEventT = TypeVar("_ClientEventT", bound=Union[_Model, str, Mapping[str, Any]]) - Iterate over the connection to receive strongly-typed server events, and use the - sub-namespaces to send strongly-typed client events:: - async with client.beta.voice_agents.realtime.connect(agent_name="my-agent") as conn: - await conn.input_audio_buffer.append(audio=chunk) - await conn.input_audio_buffer.commit() - await conn.response.create() - async for event in conn: - if event.type == RealtimeServerEventType.RESPONSE_DONE: - break +class _BaseWebSocketConnection(Generic[_ServerEventT, _ClientEventT]): + """Shared asynchronous WebSocket transport for the two voice protocols. + + :param connection: The open WebSocket. + :type connection: ~aiohttp.ClientWebSocketResponse + :param session: The HTTP session that owns the WebSocket. + :type session: ~aiohttp.ClientSession """ + _logger = _LOGGER + _server_event_types = _SERVER_EVENT_TYPES + _protocol_name = "realtime" + def __init__(self, connection: "ClientWebSocketResponse", session: "ClientSession") -> None: self._connection = connection self._session = session - self.session: SessionResource = SessionResource(self) - self.input_audio_buffer: InputAudioBufferResource = InputAudioBufferResource(self) - self.output_audio_buffer: OutputAudioBufferResource = OutputAudioBufferResource(self) - self.conversation: ConversationResource = ConversationResource(self) - self.response: ResponseResource = ResponseResource(self) + self._close_task: Optional[asyncio.Task[None]] = None - async def __aenter__(self) -> "AsyncBetaRealtimeConnection": + async def __aenter__(self) -> "_BaseWebSocketConnection[_ServerEventT, _ClientEventT]": return self async def __aexit__(self, *exc_details: Any) -> None: @@ -605,7 +589,7 @@ async def __aexit__(self, *exc_details: Any) -> None: def __repr__(self) -> str: state = "closed" if self.closed else "open" - return f"" + return f"<{type(self).__name__} [{state}]>" @property def closed(self) -> bool: @@ -615,36 +599,25 @@ def closed(self) -> bool: """ return self._connection.closed - def __aiter__(self) -> AsyncIterator[ServerEvent]: + def __aiter__(self) -> AsyncIterator[_ServerEventT]: return self._iter() - async def _iter(self) -> AsyncIterator[ServerEvent]: + async def _iter(self) -> AsyncIterator[_ServerEventT]: while True: try: yield await self.recv() except ConnectionResetError as exc: - # recv() below only chains a cause for a non-graceful closure or transport error - # (an abnormal close code, or the real exception behind a WSMsgType.ERROR); a - # graceful closure chains none. A `for event in conn:` caller must still see real - # failures instead of silently observing end-of-stream, so only the former ends - # iteration quietly. if exc.__cause__ is None: return raise - async def recv(self) -> ServerEvent: - """Receive and parse the next server event. - - Known event types are returned as their strongly-typed - ``VoiceAgentServerEventXxx`` model. Event types not (yet) represented by a - generated model are returned as a plain ``dict`` for forward compatibility. + async def recv(self) -> _ServerEventT: + """Receive a typed event, or a mapping for an unknown event. - :return: The parsed server event. - :rtype: ~azure.ai.projects.aio.ServerEvent - :raises ConnectionResetError: If the connection was closed by the server, gracefully or - otherwise, or if the transport reported an error. Iterating over the connection - (``async for event in conn:``) treats only a graceful closure as end-of-stream and - re-raises this for an abnormal one. + :return: The server event. + :rtype: object + :raises ConnectionResetError: On graceful or abnormal socket closure. + :raises ValueError: If the server event is not a JSON object. """ import aiohttp # pylint: disable=import-outside-toplevel @@ -659,35 +632,35 @@ async def recv(self) -> ServerEvent: code = self._connection.close_code if code not in (1000, 1001): raise ConnectionResetError( - f"The realtime connection was closed abnormally (code {code!r})." + f"The {self._protocol_name} connection was closed abnormally (code {code!r})." ) from _AbnormalWebSocketClosure(code) - raise ConnectionResetError("The realtime connection was closed.") + raise ConnectionResetError(f"The {self._protocol_name} connection was closed.") if msg.type == aiohttp.WSMsgType.ERROR: - raise ConnectionResetError( - "The realtime connection encountered an error." - ) from self._connection.exception() + error = self._connection.exception() + raise ConnectionResetError(f"The {self._protocol_name} connection encountered an error.") from ( + error if error is not None else _AbnormalWebSocketClosure() + ) raw = msg.data.decode("utf-8") if msg.type == aiohttp.WSMsgType.BINARY else msg.data payload: Dict[str, Any] = json.loads(raw) + if not isinstance(payload, dict): + raise ValueError("The WebSocket server event must be a JSON object.") event_type = payload.get("type") - _LOGGER.debug( + self._logger.debug( "WebSocket RECEIVE type=%s bytes=%d", event_type if isinstance(event_type, str) else "unknown", len(raw.encode("utf-8")), ) - if not isinstance(event_type, str): - return payload - event_cls = _SERVER_EVENT_TYPES.get(event_type) - if event_cls is None: - return payload - return event_cls(payload) + event_cls = self._server_event_types.get(event_type) if isinstance(event_type, str) else None + return cast(_ServerEventT, event_cls(payload) if event_cls else payload) - async def send(self, event: ClientEvent) -> None: - """Send a client event over the connection. + async def send(self, event: _ClientEventT) -> None: + """Send a generated event, mapping, or JSON string. - :param event: A strongly-typed client event, a ready-made mapping, or a raw JSON string. - :type event: ~azure.ai.projects.aio.ClientEvent or str - :raises ValueError: If ``event`` is a ``str`` that is not valid JSON. + :param event: The client event. + :type event: object + :raises ValueError: If the JSON string is invalid. """ + payload: str if isinstance(event, str): try: event_payload = json.loads(event) @@ -698,7 +671,7 @@ async def send(self, event: ClientEvent) -> None: payload = json.dumps(event, cls=SdkJSONEncoder) event_payload = json.loads(payload) event_type = event_payload.get("type") if isinstance(event_payload, dict) else None - _LOGGER.debug( + self._logger.debug( "WebSocket SEND type=%s bytes=%d", event_type if isinstance(event_type, str) else "unknown", len(payload.encode("utf-8")), @@ -706,23 +679,120 @@ async def send(self, event: ClientEvent) -> None: await self._connection.send_str(payload) async def close(self, *, code: int = 1000, reason: str = "") -> None: - """Close the connection and release the underlying HTTP session. + """Close the socket and its HTTP session once. - :keyword int code: The WebSocket close code. - :keyword str reason: The close reason. + Concurrent callers await the same cleanup. Caller cancellation is + propagated after both resources have finished closing. + + :keyword int code: WebSocket close code. + :keyword str reason: WebSocket close reason. """ - _LOGGER.debug("WebSocket CLOSE code=%d", code) + if self._close_task is not None and self._close_task.done(): + return + if self._close_task is None: + self._close_task = asyncio.create_task(self._close_resources(code, reason)) + cancelled = False + while True: + try: + await asyncio.shield(self._close_task) + break + except asyncio.CancelledError: + if self._close_task.cancelled(): + await self._close_task + raise + cancelled = True + if cancelled: + raise asyncio.CancelledError + + async def _close_resources(self, code: int, reason: str) -> None: + self._logger.debug("WebSocket CLOSE code=%d", code) try: await self._connection.close(code=code, message=reason.encode("utf-8")) finally: await self._session.close() -class AsyncBetaRealtimeConnectionManager: # pylint: disable=too-many-instance-attributes - """Async context manager that opens an :class:`AsyncBetaRealtimeConnection`. +class AsyncBetaRealtimeConnection( # pylint: disable=too-many-instance-attributes + _BaseWebSocketConnection[ServerEvent, ClientEvent] +): + """An open realtime WebSocket connection to a voice agent. + + Iterate to receive events. Use ``conversation``, ``response``, and the audio + buffers to send messages and control replies:: + + async with client.beta.voice_agents.realtime.connect(agent_name="my-agent") as conn: + await conn.input_audio_buffer.append(audio=chunk) + await conn.input_audio_buffer.commit() + await conn.response.create() + async for event in conn: + if event.type == RealtimeServerEventType.RESPONSE_DONE: + break + """ + + def __init__(self, connection: "ClientWebSocketResponse", session: "ClientSession") -> None: + super().__init__(connection, session) + self.session: SessionResource = SessionResource(self) + self.input_audio_buffer: InputAudioBufferResource = InputAudioBufferResource(self) + self.output_audio_buffer: OutputAudioBufferResource = OutputAudioBufferResource(self) + self.conversation: ConversationResource = ConversationResource(self) + self.response: ResponseResource = ResponseResource(self) + + async def __aenter__(self) -> "AsyncBetaRealtimeConnection": + return self + + async def __aexit__(self, *exc_details: Any) -> None: + await super().__aexit__(*exc_details) + + @property + def closed(self) -> bool: + """Whether the underlying WebSocket connection has been closed. + + :rtype: bool + """ + return super().closed + + def __aiter__(self) -> AsyncIterator[ServerEvent]: + return super().__aiter__() + + async def recv(self) -> ServerEvent: + """Receive and parse the next server event. + + Known events use SDK model classes. Unknown event types are returned + as dictionaries. + + :return: The parsed server event. + :rtype: ~azure.ai.projects.aio.ServerEvent + :raises ConnectionResetError: If the connection was closed by the server, gracefully or + otherwise, or if the transport reported an error. Iterating over the connection + (``async for event in conn:``) treats only a graceful closure as end-of-stream and + re-raises this for an abnormal one. + :raises ValueError: If the server event is not a JSON object. + """ + return await super().recv() + + async def send(self, event: ClientEvent) -> None: + """Send a client event over the connection. + + :param event: A client event model, mapping, or JSON string. + :type event: ~azure.ai.projects.aio.ClientEvent or str + :raises ValueError: If ``event`` is a ``str`` that is not valid JSON. + """ + await super().send(event) + + async def close(self, *, code: int = 1000, reason: str = "") -> None: + """Close the connection and release the underlying HTTP session. + + :keyword int code: The WebSocket close code. + :keyword str reason: The close reason. + """ + await super().close(code=code, reason=reason) - Returned by :meth:`AsyncBetaRealtime.connect`; you normally use it as - ``async with client.beta.voice_agents.realtime.connect(...) as conn:``. + +_ConnectionT = TypeVar("_ConnectionT", bound=_BaseWebSocketConnection[Any, Any]) + + +class _BaseWebSocketConnectionManager(Generic[_ConnectionT]): # pylint: disable=too-many-instance-attributes + """Shared asynchronous voice protocol handshake and connection lifetime. :keyword str endpoint: The Foundry project endpoint. :keyword credential: The credential used for the WebSocket handshake. @@ -733,7 +803,7 @@ class AsyncBetaRealtimeConnectionManager: # pylint: disable=too-many-instance-a :keyword str agent_name: The name of the voice agent. :keyword agent_session_id: An optional session correlation identifier. :paramtype agent_session_id: str or None - :keyword transport: The optional connection transport. The SDK encodes its wire value internally. + :keyword transport: The optional Realtime connection transport. :paramtype transport: str or ~azure.ai.projects.models.VoiceAgentTransport or None :keyword structured_inputs: Optional structured prompt inputs. :paramtype structured_inputs: Mapping[str, Any] or None @@ -745,6 +815,10 @@ class AsyncBetaRealtimeConnectionManager: # pylint: disable=too-many-instance-a :paramtype extra_headers: Mapping[str, str] or None """ + _logger = _LOGGER + _subprotocol: Optional[str] = "realtime" + _protocol_name = "realtime" + def __init__( # pylint: disable=too-many-arguments self, *, @@ -773,12 +847,12 @@ def __init__( # pylint: disable=too-many-arguments self._extra_query = dict(extra_query or {}) self._extra_headers = dict(extra_headers or {}) self._kwargs = kwargs - self._connection: Optional[AsyncBetaRealtimeConnection] = None + self._connection: Optional[_ConnectionT] = None - async def __aenter__(self) -> AsyncBetaRealtimeConnection: + async def __aenter__(self) -> _ConnectionT: return await self.enter() - async def enter(self) -> AsyncBetaRealtimeConnection: # pylint: disable=too-many-locals + async def enter(self) -> _ConnectionT: # pylint: disable=too-many-locals """Open the connection. :return: The live realtime connection. @@ -792,81 +866,143 @@ async def enter(self) -> AsyncBetaRealtimeConnection: # pylint: disable=too-man import aiohttp # pylint: disable=import-outside-toplevel except ImportError as exc: # pragma: no cover - dependency guard raise RuntimeError( - "The realtime client requires `aiohttp`. Install it with `pip install aiohttp`." + f"The {self._protocol_name} client requires `aiohttp`. Install it with `pip install aiohttp`." ) from exc # ``connection_url`` fully overrides the computed route (scheme/host/path). This is the # escape hatch used to reach a specific data-plane host/path directly. if self._connection_url is not None: _assert_trusted_connection_url(self._connection_url, self._endpoint) - url = self._connection_url or _to_ws_url(self._endpoint, self._agent_name) + url = self._connection_url or self._get_url() if self._transport is not None: url = _without_transport_query(url) if not url.startswith("wss://"): - raise ValueError("The realtime WebSocket URL must use wss:// to protect credentials in transit.") + raise ValueError( + f"The {self._protocol_name} WebSocket URL must use wss:// to protect credentials in transit." + ) - params: Dict[str, str] = {"api-version": self._api_version, "x-ms-client-sdk": _USER_AGENT} - if self._agent_session_id is not None: - params["agent_session_id"] = self._agent_session_id - if self._structured_inputs is not None: - # The service reads this from the `structured_input` query parameter (see the - # generated `build_beta_voice_agents_realtime_connect_voice_agent_request`), not a - # header -- aiohttp appends `params` to the URL for us below. - params["structured_input"] = json.dumps(self._structured_inputs, cls=SdkJSONEncoder) - params.update(self._extra_query) - if self._transport is not None: - params["transport"] = self._transport + # Protocol-specific query values include the x-ms-client-sdk identification. + params = self._get_query() target_url = urlparse(url)._replace(query="", fragment="").geturl() - _LOGGER.debug("WebSocket CONNECT target=%s", target_url) - - token = await self._credential.get_token(*self._credential_scopes) - headers: Dict[str, str] = { - "Authorization": "Bearer " + token.token, - _FOUNDRY_FEATURES_HEADER_NAME: _VOICE_AGENT_FEATURE_HEADER, - } - headers.update(self._extra_headers) - if not _has_header_case_insensitive(headers, "User-Agent"): - # Only set our default if the caller didn't supply their own (in any casing) -- - # a plain dict merge would otherwise leave both as separate keys (HTTP header names - # are case-insensitive, but Python dict keys are not), sending two User-Agent-like - # headers instead of cleanly honoring the caller's override. - headers["User-Agent"] = _USER_AGENT + self._logger.debug("WebSocket CONNECT target=%s", target_url) session = aiohttp.ClientSession() try: - # Force the "realtime" WebSocket subprotocol regardless of any caller-supplied - # override in ``self._kwargs``: the service requires this exact subprotocol, so - # silently accepting a different one here would just move the failure to a less - # clear error inside aiohttp's handshake. + token = await self._credential.get_token(*self._credential_scopes) + headers: Dict[str, str] = { + "Authorization": "Bearer " + token.token, + _FOUNDRY_FEATURES_HEADER_NAME: _VOICE_AGENT_FEATURE_HEADER, + } + headers.update(self._extra_headers) + if not _has_header_case_insensitive(headers, "User-Agent"): + # Header names are case-insensitive; preserve caller overrides in any casing. + headers["User-Agent"] = _USER_AGENT + + # Each protocol owns its handshake subprotocol, not the caller's kwargs. ws_connect_kwargs = dict(self._kwargs) ws_connect_kwargs.pop("protocols", None) - connection = await session.ws_connect( - url, headers=headers, params=params, protocols=("realtime",), **ws_connect_kwargs - ) - except BaseException as exc: + try: + connection = await session.ws_connect( + url, + headers=headers, + params=params, + protocols=(self._subprotocol,) if self._subprotocol else (), + **ws_connect_kwargs, + ) + except Exception as exc: + if isinstance(exc, (ValueError, RuntimeError)): + raise + raise ConnectionError( + f"Failed to open the {self._protocol_name} WebSocket connection to voice agent " + f"'{self._agent_name}' at '{url}': {exc}" + ) from exc + self._connection = self._create_connection(cast("ClientWebSocketResponse", connection), session) + self._logger.debug("WebSocket CONNECTED target=%s", target_url) + except BaseException: await session.close() - if not isinstance(exc, Exception) or isinstance(exc, (ValueError, RuntimeError)): - raise - raise ConnectionError( - f"Failed to open the realtime WebSocket connection to voice agent " - f"'{self._agent_name}' at '{url}': {exc}" - ) from exc - _LOGGER.debug("WebSocket CONNECTED target=%s", target_url) - self._connection = AsyncBetaRealtimeConnection(cast("ClientWebSocketResponse", connection), session) + raise return self._connection + def _get_url(self) -> str: + return _to_ws_url(self._endpoint, self._agent_name) + + def _get_query(self) -> Dict[str, str]: + params: Dict[str, str] = {"api-version": self._api_version, "x-ms-client-sdk": _USER_AGENT} + if self._agent_session_id is not None: + params["agent_session_id"] = self._agent_session_id + if self._structured_inputs is not None: + params["structured_inputs"] = json.dumps(self._structured_inputs, cls=SdkJSONEncoder) + params.update(self._extra_query) + if self._transport is not None: + params["transport"] = self._transport + return params + + def _create_connection(self, connection: "ClientWebSocketResponse", session: "ClientSession") -> _ConnectionT: + raise NotImplementedError + async def __aexit__(self, *exc_details: Any) -> None: - if self._connection is not None: - await self._connection.close() - self._connection = None + connection = self._connection + if connection is not None: + try: + await connection.close() + finally: + if self._connection is connection: + self._connection = None + + +class AsyncBetaRealtimeConnectionManager(_BaseWebSocketConnectionManager[AsyncBetaRealtimeConnection]): + """Async context manager that opens an :class:`AsyncBetaRealtimeConnection`. + + Returned by :meth:`AsyncBetaRealtime.connect`; you normally use it as + ``async with client.beta.voice_agents.realtime.connect(...) as conn:``. + + :keyword str endpoint: The Foundry project endpoint. + :keyword credential: The credential used for the WebSocket handshake. + :paramtype credential: ~azure.core.credentials_async.AsyncTokenCredential + :keyword credential_scopes: The token scopes for the handshake. + :paramtype credential_scopes: list[str] + :keyword str api_version: The API version for the handshake. + :keyword str agent_name: The name of the voice agent. + :keyword agent_session_id: An optional session correlation identifier. + :paramtype agent_session_id: str or None + :keyword transport: The optional connection transport. The SDK encodes its wire value internally. + :paramtype transport: str or ~azure.ai.projects.models.VoiceAgentTransport or None + :keyword structured_inputs: Optional structured prompt inputs. + :paramtype structured_inputs: Mapping[str, Any] or None + :keyword connection_url: An optional WebSocket URL overriding the computed route. + :paramtype connection_url: str or None + :keyword extra_query: Additional handshake query parameters. + :paramtype extra_query: Mapping[str, str] or None + :keyword extra_headers: Additional handshake headers. + :paramtype extra_headers: Mapping[str, str] or None + """ + + async def __aenter__(self) -> AsyncBetaRealtimeConnection: + return await self.enter() + + async def enter(self) -> AsyncBetaRealtimeConnection: + """Open the connection. + + :return: The live realtime connection. + :rtype: ~azure.ai.projects.aio.AsyncBetaRealtimeConnection + :raises RuntimeError: If ``aiohttp`` is not installed. + :raises ValueError: If the computed or supplied WebSocket URL does not use ``wss://``. + :raises ConnectionError: If the WebSocket upgrade handshake fails (for example, a + network error, DNS failure, or a non-101 response from the service). + """ + return await super().enter() + + def _create_connection( + self, connection: "ClientWebSocketResponse", session: "ClientSession" + ) -> AsyncBetaRealtimeConnection: + return AsyncBetaRealtimeConnection(connection, session) class AsyncBetaRealtime: # pylint: disable=too-few-public-methods - """BetaRealtime streaming entry point, exposed as ``client.beta.voice_agents.realtime``. + """Connect to a voice agent through ``client.beta.voice_agents.realtime``. - Follows the OpenAI Python realtime surface: obtain it from the HTTP client and open a - connection with :meth:`connect`:: + Open a connection with :meth:`connect`:: from azure.ai.projects.aio import AIProjectClient from azure.identity.aio import DefaultAzureCredential @@ -880,9 +1016,7 @@ class AsyncBetaRealtime: # pylint: disable=too-few-public-methods if event.type == RealtimeServerEventType.RESPONSE_DONE: break - :param client: The object whose endpoint and credential are reused for the realtime - handshake -- the ``.beta.voice_agents`` sub-client, which shares the same underlying - configuration as the top-level client. + :param client: The voice-agent client that supplies the project endpoint and credential. :type client: ~azure.ai.projects.aio.operations.BetaVoiceAgentsOperations """ @@ -911,16 +1045,11 @@ def connect( # pylint: disable=too-many-arguments :keyword agent_session_id: An optional identifier used to correlate the voice session. Default value is None. :paramtype agent_session_id: str or None - :keyword transport: The transport used for this connection. Known values are - ``VoiceAgentTransport.WEBSOCKET`` and ``VoiceAgentTransport.WEBRTC``. When omitted, the - service defaults to WebSocket. The SDK constructs the wire query internally; an explicit - selection overrides an existing transport query value. For WebRTC, the caller must - manage the peer connection, media, and SDP offer/answer exchange. + :keyword transport: ``VoiceAgentTransport.WEBSOCKET`` (service default) or + ``VoiceAgentTransport.WEBRTC``. An explicit value overrides ``extra_query``. + WebRTC requires your app to handle the peer connection, media, and SDP exchange. :paramtype transport: str or ~azure.ai.projects.models.VoiceAgentTransport or None - :keyword structured_inputs: A mapping of structured-input names to their values for this - session (see :attr:`~azure.ai.projects.models.CreateTelephonyCallJobRequest.structured_inputs` - for the analogous shape used elsewhere). Serialized to JSON on the wire. Default value is - None. + :keyword structured_inputs: Values for the agent's structured-input placeholders. :paramtype structured_inputs: Mapping[str, Any] or None :keyword connection_url: Full ``wss://`` URL that overrides the route computed from the client endpoint. Query parameters are still appended. Default value is None. 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 a4c93a7c971c..7d6532c59514 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 @@ -147,6 +147,13 @@ build_beta_skills_list_request, build_beta_skills_list_versions_request, build_beta_skills_update_request, + build_beta_voice_agents_campaigns_cancel_request, + build_beta_voice_agents_campaigns_create_request, + build_beta_voice_agents_campaigns_delete_request, + build_beta_voice_agents_campaigns_get_operation_request, + build_beta_voice_agents_campaigns_get_request, + build_beta_voice_agents_campaigns_list_request, + build_beta_voice_agents_campaigns_list_validation_errors_request, build_beta_voice_agents_conversations_delete_request, build_beta_voice_agents_conversations_download_audio_item_request, build_beta_voice_agents_conversations_download_audio_request, @@ -161,16 +168,27 @@ build_beta_voice_agents_conversations_list_request, build_beta_voice_agents_conversations_list_response_items_request, build_beta_voice_agents_conversations_list_responses_request, + build_beta_voice_agents_live_conversations_delete_request, + build_beta_voice_agents_live_conversations_download_audio_item_request, + build_beta_voice_agents_live_conversations_download_audio_request, + build_beta_voice_agents_live_conversations_get_audio_item_request, + build_beta_voice_agents_live_conversations_get_audio_request, + build_beta_voice_agents_live_conversations_get_item_request, + build_beta_voice_agents_live_conversations_get_request, + build_beta_voice_agents_live_conversations_list_items_request, + build_beta_voice_agents_live_conversations_list_request, build_beta_voice_agents_telephony_cancel_call_job_request, build_beta_voice_agents_telephony_create_binding_request, build_beta_voice_agents_telephony_create_call_job_request, build_beta_voice_agents_telephony_delete_binding_request, + build_beta_voice_agents_telephony_delete_call_job_request, build_beta_voice_agents_telephony_end_call_request, build_beta_voice_agents_telephony_get_binding_request, build_beta_voice_agents_telephony_get_call_job_request, build_beta_voice_agents_telephony_get_call_request, build_beta_voice_agents_telephony_get_transfer_targets_request, build_beta_voice_agents_telephony_list_bindings_request, + build_beta_voice_agents_telephony_list_call_jobs_request, build_beta_voice_agents_telephony_list_calls_request, build_beta_voice_agents_telephony_replace_transfer_targets_request, build_beta_voice_agents_telephony_transfer_call_request, @@ -2162,7 +2180,9 @@ async def get_session_log_stream( Each SSE frame contains: * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) + * `data`: a plain-text log line (currently JSON-formatted, but the schema + is not contractual and may include additional keys or change format + over time — clients should treat it as an opaque string) Example SSE frames: @@ -8984,9 +9004,15 @@ def __init__(self, *args, **kwargs) -> None: self.conversations = BetaVoiceAgentsConversationsOperations( self._client, self._config, self._serialize, self._deserialize ) + self.live_conversations = BetaVoiceAgentsLiveConversationsOperations( + self._client, self._config, self._serialize, self._deserialize + ) self.telephony = BetaVoiceAgentsTelephonyOperations( self._client, self._config, self._serialize, self._deserialize ) + self.campaigns = BetaVoiceAgentsCampaignsOperations( + self._client, self._config, self._serialize, self._deserialize + ) class BetaAgentsOperations: # pylint: disable=docstring-missing-param @@ -18424,14 +18450,14 @@ async def download_audio(self, agent_name: str, conversation_id: str, **kwargs: return deserialized # type: ignore -class BetaVoiceAgentsTelephonyOperations: # pylint: disable=docstring-missing-param +class BetaVoiceAgentsLiveConversationsOperations: # pylint: disable=docstring-missing-param,name-too-long """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`telephony` attribute. + :attr:`live_conversations` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -18441,90 +18467,117 @@ 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 create_binding( + @distributed_trace + def list( self, agent_name: str, - telephony_binding: _models.CreateTelephonyBindingRequest, *, - content_type: str = "application/json", + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. + ) -> AsyncItemPaged["_models.VoiceAgentLiveConversation"]: + """List Live voice agent conversations. - Creates a telephony binding for the voice agent named in the path. + Lists stored Live conversations for this agent, including sessions stored via an override. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Required. - :type telephony_binding: ~azure.ai.projects.models.CreateTelephonyBindingRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :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 VoiceAgentLiveConversation + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.VoiceAgentLiveConversation] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - async def create_binding( - self, agent_name: str, telephony_binding: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. + cls: ClsType[List[_models.VoiceAgentLiveConversation]] = kwargs.pop("cls", None) - Creates a telephony binding for the voice agent named in the path. + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Required. - :type telephony_binding: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ + def prepare_request(_continuation_token=None): - @overload - async def create_binding( - self, agent_name: str, telephony_binding: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. + _request = build_beta_voice_agents_live_conversations_list_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 - Creates a telephony binding for the voice agent named in the path. + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.VoiceAgentLiveConversation], + 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) - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Required. - :type telephony_binding: 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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ + 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 create_binding( - self, - agent_name: str, - telephony_binding: Union[_models.CreateTelephonyBindingRequest, JSON, IO[bytes]], - **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. + async def get(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceAgentLiveConversation: + """Get a Live voice agent conversation. - Creates a telephony binding for the voice agent named in the path. + Gets a stored Live conversation; fetch items separately. Returns 404 if absent or not stored. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Is one of the following - types: CreateTelephonyBindingRequest, JSON, IO[bytes] Required. - :type telephony_binding: ~azure.ai.projects.models.CreateTelephonyBindingRequest or JSON or - IO[bytes] - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :return: VoiceAgentLiveConversation. The VoiceAgentLiveConversation is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAgentLiveConversation :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -18535,24 +18588,15 @@ async def create_binding( } 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.TelephonyBinding] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(telephony_binding, (IOBase, bytes)): - _content = telephony_binding - else: - _content = json.dumps(telephony_binding, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.VoiceAgentLiveConversation] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_create_binding_request( + _request = build_beta_voice_agents_live_conversations_get_request( agent_name=agent_name, - content_type=content_type, + conversation_id=conversation_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -18569,7 +18613,7 @@ async def create_binding( 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 @@ -18582,43 +18626,95 @@ async def create_binding( ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyBinding, response.json()) + deserialized = _deserialize(_models.VoiceAgentLiveConversation, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace_async + async def delete(self, agent_name: str, conversation_id: str, **kwargs: Any) -> None: + """Delete a Live voice agent conversation. + + Deletes the stored conversation and its items/audio, without closing the Live session. + + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_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_voice_agents_live_conversations_delete_request( + agent_name=agent_name, + conversation_id=conversation_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 - def list_bindings( + def list_items( self, agent_name: str, + conversation_id: str, *, - provider: Optional[Union[str, _models.TelephonyProvider]] = None, - status: Optional[Union[str, _models.TelephonyBindingStatus]] = None, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.TelephonyBindingListItem"]: - """List agent telephony bindings. + ) -> AsyncItemPaged["_models.VoiceAgentLiveConversationItem"]: + """List items in a Live voice agent conversation. - Returns the telephony bindings owned by the voice agent named in the path. + Lists stored speech and delegation items in order; cursors use item IDs. Returns 404 if the + conversation is absent or not stored. - :param agent_name: The name of the voice agent whose bindings are listed. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :keyword provider: Filters bindings by provider. Known values are: "teams_phone_extensibility" - and "twilio". Default value is None. - :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider - :keyword status: Filters bindings by lifecycle status. Known values are: "active" and - "suspended". Default value is None. - :paramtype status: str or ~azure.ai.projects.models.TelephonyBindingStatus + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_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. @@ -18633,15 +18729,15 @@ def list_bindings( 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 TelephonyBindingListItem + :return: An iterator like instance of VoiceAgentLiveConversationItem :rtype: - ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyBindingListItem] + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.VoiceAgentLiveConversationItem] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.TelephonyBindingListItem]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.VoiceAgentLiveConversationItem]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -18653,10 +18749,9 @@ def list_bindings( def prepare_request(_continuation_token=None): - _request = build_beta_voice_agents_telephony_list_bindings_request( + _request = build_beta_voice_agents_live_conversations_list_items_request( agent_name=agent_name, - provider=provider, - status=status, + conversation_id=conversation_id, limit=limit, order=order, after=_continuation_token, @@ -18674,7 +18769,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.TelephonyBindingListItem], + List[_models.VoiceAgentLiveConversationItem], deserialized.get("data", []), ) if cls: @@ -18703,17 +18798,23 @@ async def get_next(_continuation_token=None): return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _models.TelephonyBinding: - """Get an agent telephony binding. + async def get_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.VoiceAgentLiveConversationItem: + """Get a Live voice agent conversation item. - Retrieves a telephony binding owned by the voice agent named in the path. + Gets a stored item by ID. Returns 404 if the item or conversation is absent. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :param item_id: The id returned on the persisted item. Required. + :type item_id: str + :return: VoiceAgentLiveConversationItem. The VoiceAgentLiveConversationItem is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAgentLiveConversationItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -18727,11 +18828,12 @@ async def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) + cls: ClsType[_models.VoiceAgentLiveConversationItem] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_get_binding_request( + _request = build_beta_voice_agents_live_conversations_get_item_request( agent_name=agent_name, - binding_id=binding_id, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -18762,149 +18864,111 @@ async def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyBinding, response.json()) + deserialized = _deserialize(_models.VoiceAgentLiveConversationItem, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - async def update_binding( - self, - agent_name: str, - binding_id: str, - body: _models.UpdateTelephonyBindingRequest, - *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + @distributed_trace_async + async def get_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.VoiceAudioItem: + """Get a Live conversation item's audio metadata. - Updates a telephony binding owned by the voice agent named in the path. + Gets captured speech-audio metadata. BYOS uses unsigned blob_uri. Returns 404 for missing + audio, conversations not stored, or delegation items. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Required. - :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :param item_id: The id returned on the persisted item. Required. + :type item_id: str + :return: VoiceAudioItem. The VoiceAudioItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAudioItem :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_binding( - self, - agent_name: str, - binding_id: str, - body: JSON, - *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - Updates a telephony binding owned by the voice agent named in the path. + cls: ClsType[_models.VoiceAudioItem] = kwargs.pop("cls", None) - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Required. - :type body: JSON - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ + _request = build_beta_voice_agents_live_conversations_get_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_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) - @overload - async def update_binding( - self, - agent_name: str, - binding_id: str, - body: IO[bytes], - *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + _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 + ) - Updates a telephony binding owned by the voice agent named in the path. + response = pipeline_response.http_response - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Required. - :type body: IO[bytes] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.VoiceAudioItem, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace_async - async def update_binding( - self, - agent_name: str, - binding_id: str, - body: Union[_models.UpdateTelephonyBindingRequest, JSON, IO[bytes]], - *, - etag: str, - match_condition: MatchConditions, - **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + async def download_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> AsyncIterator[bytes]: + """Stream a Live conversation item's audio. - Updates a telephony binding owned by the voice agent named in the path. + Streams captured speech as WAV. BYOS returns 409; use blob_uri. Returns 404 for missing audio, + conversations not stored, or delegation items. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Is one of the following types: - UpdateTelephonyBindingRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest or JSON or IO[bytes] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :param item_id: The id returned on the persisted item. Required. + :type item_id: str + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -18913,35 +18977,18 @@ async def update_binding( 409: ResourceExistsError, 304: ResourceNotModifiedError, } - if match_condition == MatchConditions.IfNotModified: - error_map[412] = ResourceModifiedError - elif match_condition == MatchConditions.IfPresent: - error_map[412] = ResourceNotFoundError - elif match_condition == MatchConditions.IfMissing: - error_map[412] = ResourceExistsError 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.TelephonyBinding] = 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 + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_update_binding_request( + _request = build_beta_voice_agents_live_conversations_download_audio_item_request( agent_name=agent_name, - binding_id=binding_id, - etag=etag, - match_condition=match_condition, - content_type=content_type, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -18951,7 +18998,7 @@ async def update_binding( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -18972,12 +19019,9 @@ async def update_binding( raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + 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.TelephonyBinding, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -18985,23 +19029,20 @@ async def update_binding( return deserialized # type: ignore @distributed_trace_async - async def delete_binding( - self, agent_name: str, binding_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any - ) -> None: - """Delete an agent telephony binding. + async def get_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceRecording: + """Get a Live conversation's merged recording metadata. - Deletes a telephony binding owned by the voice agent named in the path. + Gets merged stereo recording metadata (user left, assistant right). BYOS uses unsigned + blob_uri. Returns 404 for no audio, or 409 recording_not_ready/recording_unavailable for + pending/failed finalization; pending responses may include Retry-After. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :return: None - :rtype: None + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :return: VoiceRecording. The VoiceRecording is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceRecording :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -19010,24 +19051,16 @@ async def delete_binding( 409: ResourceExistsError, 304: ResourceNotModifiedError, } - if match_condition == MatchConditions.IfNotModified: - error_map[412] = ResourceModifiedError - elif match_condition == MatchConditions.IfPresent: - error_map[412] = ResourceNotFoundError - elif match_condition == MatchConditions.IfMissing: - error_map[412] = ResourceExistsError 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) + cls: ClsType[_models.VoiceRecording] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_delete_binding_request( + _request = build_beta_voice_agents_live_conversations_get_audio_request( agent_name=agent_name, - binding_id=binding_id, - etag=etag, - match_condition=match_condition, + conversation_id=conversation_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -19037,14 +19070,20 @@ async def delete_binding( } _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, @@ -19052,137 +19091,30 @@ async def delete_binding( ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.VoiceRecording, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore - @distributed_trace - def list_calls( - self, - agent_name: str, - *, - provider: Optional[Union[str, _models.TelephonyProvider]] = None, - status: Optional[Union[str, _models.TelephonyCallStatus]] = None, - started_after_time: Optional[datetime.datetime] = None, - started_before_time: Optional[datetime.datetime] = None, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.TelephonyCallSummary"]: - """List agent telephony calls. - - Returns the durable inbound call history for the voice agent named in the path. - - :param agent_name: The name of the voice agent whose calls are listed. Required. - :type agent_name: str - :keyword provider: Filters calls by provider. Known values are: "teams_phone_extensibility" and - "twilio". Default value is None. - :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider - :keyword status: Filters calls by lifecycle status. Known values are: "in_progress", "success", - and "failed". Default value is None. - :paramtype status: str or ~azure.ai.projects.models.TelephonyCallStatus - :keyword started_after_time: Includes calls that started at or after this Unix timestamp in - seconds. Default value is None. - :paramtype started_after_time: ~datetime.datetime - :keyword started_before_time: Includes calls that started at or before this Unix timestamp in - seconds. Default value is None. - :paramtype started_before_time: ~datetime.datetime - :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 TelephonyCallSummary - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyCallSummary] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.TelephonyCallSummary]] = 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_voice_agents_telephony_list_calls_request( - agent_name=agent_name, - provider=provider, - status=status, - started_after_time=started_after_time, - started_before_time=started_before_time, - 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.TelephonyCallSummary], - 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) + return deserialized # type: ignore @distributed_trace_async - async def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: - """Get an agent telephony call. + async def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> AsyncIterator[bytes]: + """Stream a Live conversation's merged recording. - Retrieves a durable inbound call record owned by the voice agent named in the path. + Streams the merged stereo WAV. BYOS returns 409; use blob_uri. Returns 404 for no audio, or 409 + recording_not_ready/recording_unavailable for pending/failed finalization. - :param agent_name: The name of the voice agent that owns the call record. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -19196,11 +19128,11 @@ async def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _model _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_get_call_request( + _request = build_beta_voice_agents_live_conversations_download_audio_request( agent_name=agent_name, - call_id=call_id, + conversation_id=conversation_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -19211,7 +19143,7 @@ async def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _model _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -19231,106 +19163,114 @@ async def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _model ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore + +class BetaVoiceAgentsTelephonyOperations: # pylint: disable=docstring-missing-param + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`telephony` 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 transfer_call( - self, agent_name: str, call_id: str, *, target: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. + async def create_binding( + self, + agent_name: str, + binding: _models.TelephonyBinding, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - Transfers an active inbound call to a configured target for the voice agent named in the path. + Creates a telephony binding for the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the active call. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :keyword target: The name of a transfer target configured for the voice agent. Required. - :paramtype target: str + :param binding: The provider-specific binding to create. Required. + :type binding: ~azure.ai.projects.models.TelephonyBinding :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def transfer_call( - self, agent_name: str, call_id: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. + async def create_binding( + self, agent_name: str, binding: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - Transfers an active inbound call to a configured target for the voice agent named in the path. + Creates a telephony binding for the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the active call. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :param body: Required. - :type body: JSON + :param binding: The provider-specific binding to create. Required. + :type binding: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def transfer_call( - self, agent_name: str, call_id: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. + async def create_binding( + self, agent_name: str, binding: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - Transfers an active inbound call to a configured target for the voice agent named in the path. + Creates a telephony binding for the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the active call. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :param body: Required. - :type body: IO[bytes] + :param binding: The provider-specific binding to create. Required. + :type binding: 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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def transfer_call( - self, - agent_name: str, - call_id: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - target: str = _Unset, - **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. + async def create_binding( + self, agent_name: str, binding: Union[_models.TelephonyBinding, JSON, IO[bytes]], **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - Transfers an active inbound call to a configured target for the voice agent named in the path. + Creates a telephony binding for the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the active call. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword target: The name of a transfer target configured for the voice agent. Required. - :paramtype target: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :param binding: The provider-specific binding to create. Is one of the following types: + TelephonyBinding, JSON, IO[bytes] Required. + :type binding: ~azure.ai.projects.models.TelephonyBinding or JSON or IO[bytes] + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -19345,23 +19285,17 @@ async def transfer_call( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) - if body is _Unset: - if target is _Unset: - raise TypeError("missing required argument: target") - body = {"target": target} - 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(binding, (IOBase, bytes)): + _content = binding else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(binding, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_voice_agents_telephony_transfer_call_request( + _request = build_beta_voice_agents_telephony_create_binding_request( agent_name=agent_name, - call_id=call_id, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -19381,7 +19315,7 @@ async def transfer_call( 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 @@ -19394,30 +19328,63 @@ async def transfer_call( ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) + deserialized = _deserialize(_models.TelephonyBinding, 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 end_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: - """End an active agent telephony call. + @distributed_trace + def list_bindings( + self, + agent_name: str, + *, + provider: Optional[Union[str, _models.TelephonyProvider]] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.TelephonyBindingListItem"]: + """List agent telephony bindings. - Ends an active inbound call owned by the voice agent named in the path. + Returns the telephony bindings owned by the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the active call. Required. + :param agent_name: The name of the voice agent whose bindings are listed. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :keyword provider: Filters bindings by provider. Known values are: "teams_phone_extensibility", + "twilio", and "sip". Default value is None. + :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider + :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 TelephonyBindingListItem + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyBindingListItem] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyBindingListItem]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -19426,65 +19393,68 @@ async def end_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _model } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) + def prepare_request(_continuation_token=None): - _request = build_beta_voice_agents_telephony_end_call_request( - agent_name=agent_name, - call_id=call_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) + _request = build_beta_voice_agents_telephony_list_bindings_request( + agent_name=agent_name, + provider=provider, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = 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.TelephonyBindingListItem], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) - response = pipeline_response.http_response + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [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.TelephonyCallRecord, response.json()) + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return pipeline_response - return deserialized # type: ignore + return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models.TelephonyTransferTargets: - """Get agent telephony transfer targets. + async def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _models.TelephonyBinding: + """Get an agent telephony binding. - Returns all transfer targets configured for the voice agent named in the path. + Retrieves a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the voice agent whose transfer targets are retrieved. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -19498,10 +19468,11 @@ async def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models. _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyTransferTargets] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_get_transfer_targets_request( + _request = build_beta_voice_agents_telephony_get_binding_request( agent_name=agent_name, + binding_id=binding_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -19538,7 +19509,7 @@ async def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models. if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) + deserialized = _deserialize(_models.TelephonyBinding, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -19546,131 +19517,135 @@ async def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models. return deserialized # type: ignore @overload - async def replace_transfer_targets( + async def update_binding( self, agent_name: str, + binding_id: str, + body: _models.UpdateTelephonyBindingRequest, *, - transfer_targets: List[_models.TelephonyTransferTarget], etag: str, match_condition: MatchConditions, - content_type: str = "application/json", + content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. - Replaces all transfer targets configured for the voice agent named in the path. + Updates a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :keyword transfer_targets: The complete set of destinations to which the voice agent may - transfer calls. An empty array clears all targets when replacing the configuration. Required. - :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Required. + :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest :keyword etag: check if resource is changed. Set None to skip checking etag. Required. :paramtype etag: str :keyword match_condition: The match condition to use upon the etag. Required. :paramtype match_condition: ~azure.core.MatchConditions :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: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def replace_transfer_targets( + async def update_binding( self, agent_name: str, + binding_id: str, body: JSON, *, etag: str, match_condition: MatchConditions, - content_type: str = "application/json", + content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. - Replaces all transfer targets configured for the voice agent named in the path. + Updates a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param body: Required. + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Required. :type body: JSON :keyword etag: check if resource is changed. Set None to skip checking etag. Required. :paramtype etag: str :keyword match_condition: The match condition to use upon the etag. Required. :paramtype match_condition: ~azure.core.MatchConditions :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: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def replace_transfer_targets( + async def update_binding( self, agent_name: str, + binding_id: str, body: IO[bytes], *, etag: str, match_condition: MatchConditions, - content_type: str = "application/json", + content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. - Replaces all transfer targets configured for the voice agent named in the path. + Updates a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param body: Required. + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Required. :type body: IO[bytes] :keyword etag: check if resource is changed. Set None to skip checking etag. Required. :paramtype etag: str :keyword match_condition: The match condition to use upon the etag. Required. :paramtype match_condition: ~azure.core.MatchConditions :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: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def replace_transfer_targets( + async def update_binding( self, agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, + binding_id: str, + body: Union[_models.UpdateTelephonyBindingRequest, JSON, IO[bytes]], *, - transfer_targets: List[_models.TelephonyTransferTarget] = _Unset, etag: str, match_condition: MatchConditions, **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. - Replaces all transfer targets configured for the voice agent named in the path. + Updates a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :param agent_name: The name of the voice agent that owns the binding. 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 transfer_targets: The complete set of destinations to which the voice agent may - transfer calls. An empty array clears all targets when replacing the configuration. Required. - :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Is one of the following types: + UpdateTelephonyBindingRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest or JSON or IO[bytes] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str :keyword match_condition: The match condition to use upon the etag. Required. :paramtype match_condition: ~azure.core.MatchConditions - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -19691,22 +19666,18 @@ async def replace_transfer_targets( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.TelephonyTransferTargets] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) - if body is _Unset: - if transfer_targets is _Unset: - raise TypeError("missing required argument: transfer_targets") - body = {"transfer_targets": transfer_targets} - 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_voice_agents_telephony_replace_transfer_targets_request( + _request = build_beta_voice_agents_telephony_update_binding_request( agent_name=agent_name, + binding_id=binding_id, etag=etag, match_condition=match_condition, content_type=content_type, @@ -19747,156 +19718,2039 @@ async def replace_transfer_targets( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) + deserialized = _deserialize(_models.TelephonyBinding, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @overload - async def create_call_job( - self, - agent_name: str, - body: _models.CreateTelephonyCallJobRequest, - *, - idempotency_key: str, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. + @distributed_trace_async + async def delete_binding( + self, agent_name: str, binding_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any + ) -> None: + """Delete an agent telephony binding. - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + Deletes a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the voice agent that executes the call. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param body: The direct outbound call to create. Required. - :type body: ~azure.ai.projects.models.CreateTelephonyCallJobRequest - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError + error_map.update(kwargs.pop("error_map", {}) or {}) - @overload - async def create_call_job( - self, - agent_name: str, - body: JSON, - *, - idempotency_key: str, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + cls: ClsType[None] = kwargs.pop("cls", None) - :param agent_name: The name of the voice agent that executes the call. Required. - :type agent_name: str - :param body: The direct outbound call to create. Required. - :type body: JSON - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + _request = build_beta_voice_agents_telephony_delete_binding_request( + agent_name=agent_name, + binding_id=binding_id, + etag=etag, + match_condition=match_condition, + 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) - @overload - async def create_call_job( - self, - agent_name: str, - body: IO[bytes], - *, - idempotency_key: str, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + response = pipeline_response.http_response - :param agent_name: The name of the voice agent that executes the call. Required. - :type agent_name: str - :param body: The direct outbound call to create. Required. - :type body: IO[bytes] - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + 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) - @distributed_trace_async - async def create_call_job( + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace + def list_calls( self, agent_name: str, - body: Union[_models.CreateTelephonyCallJobRequest, JSON, IO[bytes]], *, - idempotency_key: str, + provider: Optional[Union[str, _models.TelephonyProvider]] = None, + status: Optional[Union[str, _models.TelephonyCallStatus]] = None, + started_after_time: Optional[datetime.datetime] = None, + started_before_time: Optional[datetime.datetime] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. + ) -> AsyncItemPaged["_models.TelephonyCallSummary"]: + """List agent telephony calls. - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + Returns the durable inbound call history for the voice agent named in the path. - :param agent_name: The name of the voice agent that executes the call. Required. + :param agent_name: The name of the voice agent whose calls are listed. Required. :type agent_name: str - :param body: The direct outbound call to create. Is one of the following types: - CreateTelephonyCallJobRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.CreateTelephonyCallJobRequest or JSON or IO[bytes] - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_key: str - :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :keyword provider: Filters calls by provider. Known values are: "teams_phone_extensibility", + "twilio", and "sip". Default value is None. + :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider + :keyword status: Filters calls by lifecycle status. Known values are: "in_progress", "success", + and "failed". Default value is None. + :paramtype status: str or ~azure.ai.projects.models.TelephonyCallStatus + :keyword started_after_time: Includes calls that started at or after this Unix timestamp in + seconds. Default value is None. + :paramtype started_after_time: ~datetime.datetime + :keyword started_before_time: Includes calls that started at or before this Unix timestamp in + seconds. Default value is None. + :paramtype started_before_time: ~datetime.datetime + :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 TelephonyCallSummary + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyCallSummary] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCallSummary]] = 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_voice_agents_telephony_list_calls_request( + agent_name=agent_name, + provider=provider, + status=status, + started_after_time=started_after_time, + started_before_time=started_before_time, + 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.TelephonyCallSummary], + 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_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: + """Get an agent telephony call. + + Retrieves a durable inbound call record owned by the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the call record. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :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.TelephonyCallRecord] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_telephony_get_call_request( + agent_name=agent_name, + call_id=call_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.TelephonyCallRecord, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + async def transfer_call( + self, agent_name: str, call_id: str, *, target: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. + + Transfers an active inbound call to a configured target for the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :keyword target: The name of a transfer target configured for the voice agent. Required. + :paramtype target: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def transfer_call( + self, agent_name: str, call_id: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. + + Transfers an active inbound call to a configured target for the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def transfer_call( + self, agent_name: str, call_id: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. + + Transfers an active inbound call to a configured target for the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def transfer_call( + self, + agent_name: str, + call_id: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + target: str = _Unset, + **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. + + Transfers an active inbound call to a configured target for the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword target: The name of a transfer target configured for the voice agent. Required. + :paramtype target: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :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.TelephonyCallRecord] = kwargs.pop("cls", None) + + if body is _Unset: + if target is _Unset: + raise TypeError("missing required argument: target") + body = {"target": target} + 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_voice_agents_telephony_transfer_call_request( + agent_name=agent_name, + call_id=call_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.TelephonyCallRecord, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def end_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: + """End an active agent telephony call. + + Ends an active inbound call owned by the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :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.TelephonyCallRecord] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_telephony_end_call_request( + agent_name=agent_name, + call_id=call_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.TelephonyCallRecord, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models.TelephonyTransferTargets: + """Get agent telephony transfer targets. + + Returns all transfer targets configured for the voice agent named in the path. + + :param agent_name: The name of the voice agent whose transfer targets are retrieved. Required. + :type agent_name: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :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.TelephonyTransferTargets] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_telephony_get_transfer_targets_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 = 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["ETag"] = self._deserialize("str", response.headers.get("ETag")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @overload + async def replace_transfer_targets( + self, + agent_name: str, + *, + transfer_targets: List[_models.TelephonyTransferTarget], + etag: str, + match_condition: MatchConditions, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. + + Replaces all transfer targets configured for the voice agent named in the path. + + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :type agent_name: str + :keyword transfer_targets: The complete set of destinations to which the voice agent may + transfer calls. An empty array clears all targets when replacing the configuration. Required. + :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def replace_transfer_targets( + self, + agent_name: str, + body: JSON, + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. + + Replaces all transfer targets configured for the voice agent named in the path. + + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :type agent_name: str + :param body: Required. + :type body: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def replace_transfer_targets( + self, + agent_name: str, + body: IO[bytes], + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. + + Replaces all transfer targets configured for the voice agent named in the path. + + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :type agent_name: str + :param body: Required. + :type body: IO[bytes] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def replace_transfer_targets( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + transfer_targets: List[_models.TelephonyTransferTarget] = _Unset, + etag: str, + match_condition: MatchConditions, + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. + + Replaces all transfer targets configured for the voice agent named in the path. + + :param agent_name: The name of the voice agent whose transfer targets are replaced. 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 transfer_targets: The complete set of destinations to which the voice agent may + transfer calls. An empty array clears all targets when replacing the configuration. Required. + :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError + 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.TelephonyTransferTargets] = kwargs.pop("cls", None) + + if body is _Unset: + if transfer_targets is _Unset: + raise TypeError("missing required argument: transfer_targets") + body = {"transfer_targets": transfer_targets} + 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_voice_agents_telephony_replace_transfer_targets_request( + agent_name=agent_name, + etag=etag, + match_condition=match_condition, + 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) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @overload + async def create_call_job( + self, + agent_name: str, + job: _models.TelephonyCallJobCreate, + *, + idempotency_key: str, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. + + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. + + :param agent_name: The name of the voice agent that executes the call. Required. + :type agent_name: str + :param job: The direct outbound call to create. Required. + :type job: ~azure.ai.projects.models.TelephonyCallJobCreate + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_call_job( + self, agent_name: str, job: JSON, *, idempotency_key: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. + + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. + + :param agent_name: The name of the voice agent that executes the call. Required. + :type agent_name: str + :param job: The direct outbound call to create. Required. + :type job: JSON + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_call_job( + self, + agent_name: str, + job: IO[bytes], + *, + idempotency_key: str, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. + + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. + + :param agent_name: The name of the voice agent that executes the call. Required. + :type agent_name: str + :param job: The direct outbound call to create. Required. + :type job: IO[bytes] + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_call_job( + self, + agent_name: str, + job: Union[_models.TelephonyCallJobCreate, JSON, IO[bytes]], + *, + idempotency_key: str, + **kwargs: Any + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. + + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. + + :param agent_name: The name of the voice agent that executes the call. Required. + :type agent_name: str + :param job: The direct outbound call to create. Is one of the following types: + TelephonyCallJobCreate, JSON, IO[bytes] Required. + :type job: ~azure.ai.projects.models.TelephonyCallJobCreate or JSON or IO[bytes] + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_key: str + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob + :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.TelephonyCallJob] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(job, (IOBase, bytes)): + _content = job + else: + _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_voice_agents_telephony_create_call_job_request( + agent_name=agent_name, + idempotency_key=idempotency_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 = 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) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Retry-After"] = self._deserialize("duration-seconds-int", response.headers.get("Retry-After")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_call_jobs( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.TelephonyCallJobStatus]] = None, + campaign_name: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.TelephonyCallJob"]: + """List outbound telephony call jobs. + + Lists current direct/Campaign jobs, excluding deleted or superseded rounds. Pages are live. + Campaign cursors survive boundary deletion/cancel, not replacement/name reuse (400 + invalid_cursor). + + :param agent_name: The owning voice agent. Authorization is applied before pagination. + 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 + :keyword status: Optional lifecycle filter. Known values are: "accepted", + "waiting_for_schedule", "queued", "dispatching", "in_progress", "waiting_for_retry", + "cancellation_requested", "completed", "blocked", "expired", "failed", and "cancelled". Default + value is None. + :paramtype status: str or ~azure.ai.projects.models.TelephonyCallJobStatus + :keyword campaign_name: Current Campaign round: 404 if absent, empty while deleting. Omit for + direct and Campaign jobs. Replacement/name reuse invalidates cursors. Default value is None. + :paramtype campaign_name: str + :return: An iterator like instance of TelephonyCallJob + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyCallJob] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCallJob]] = 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_voice_agents_telephony_list_call_jobs_request( + agent_name=agent_name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + status=status, + campaign_name=campaign_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.TelephonyCallJob], + 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_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) -> None: + """Delete an outbound telephony call job. + + Deletes a terminal, reconciled job (otherwise 409), without cancelling calls or removing + Campaign outcomes/call history. Later GET returns 404; repeated DELETE returns 204. + + :param agent_name: The owning voice agent. Required. + :type agent_name: str + :param call_job_id: The call-job identifier. Required. + :type call_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_voice_agents_telephony_delete_call_job_request( + agent_name=agent_name, + call_job_id=call_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 get_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) -> _models.TelephonyCallJob: + """Get an outbound telephony call job. + + Retrieves a durable direct or campaign-created outbound call job. + + :param agent_name: The name of the voice agent that owns the call job. Required. + :type agent_name: str + :param call_job_id: The service-generated identifier of the call job to retrieve. Required. + :type call_job_id: str + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob + :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.TelephonyCallJob] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_telephony_get_call_job_request( + agent_name=agent_name, + call_job_id=call_job_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def cancel_call_job( + self, agent_name: str, call_job_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any + ) -> _models.TelephonyCallJob: + """Cancel an outbound telephony call job. + + Cancels future attempts using If-Match; completion may be asynchronous. New cancellation after + connection returns 409 and lets the active call finish. + + :param agent_name: The name of the voice agent that owns the call job. Required. + :type agent_name: str + :param call_job_id: The service-generated identifier of the call job to cancel. Required. + :type call_job_id: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_telephony_cancel_call_job_request( + agent_name=agent_name, + call_job_id=call_job_id, + etag=etag, + match_condition=match_condition, + 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, 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) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + if response.status_code == 200: + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + + if response.status_code == 202: + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Retry-After"] = self._deserialize( + "duration-seconds-int", response.headers.get("Retry-After") + ) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + +class BetaVoiceAgentsCampaignsOperations: # pylint: disable=docstring-missing-param + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`campaigns` 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") + + async def _create_initial( + self, + agent_name: str, + campaign_name: str, + campaign: Union[_models.TelephonyCampaign, JSON, IO[bytes]], + *, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> AsyncIterator[bytes]: + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(campaign, (IOBase, bytes)): + _content = campaign + else: + _content = json.dumps(campaign, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_voice_agents_campaigns_create_request( + agent_name=agent_name, + campaign_name=campaign_name, + operation_id=operation_id, + etag=etag, + match_condition=match_condition, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = True + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + 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["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: _models.TelephonyCampaign, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Required. + :type campaign: ~azure.ai.projects.models.TelephonyCampaign + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. 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 etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of AsyncLROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: JSON, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Required. + :type campaign: JSON + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. 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 etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of AsyncLROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Required. + :type campaign: IO[bytes] + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. 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 + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of AsyncLROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: Union[_models.TelephonyCampaign, JSON, IO[bytes]], + *, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Is one of the following types: TelephonyCampaign, JSON, IO[bytes] Required. + :type campaign: ~azure.ai.projects.models.TelephonyCampaign or JSON or IO[bytes] + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. Default value is None. + :paramtype operation_id: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of AsyncLROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :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.TelephonyCampaign] = 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._create_initial( + agent_name=agent_name, + campaign_name=campaign_name, + campaign=campaign, + operation_id=operation_id, + etag=etag, + match_condition=match_condition, + content_type=content_type, + cls=lambda x, y, z: x, + headers=_headers, + params=_params, + **kwargs + ) + await raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) + + def get_long_running_output(pipeline_response): + response_headers = {} + response = pipeline_response.http_response + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + deserialized = _deserialize(_models.TelephonyCampaign, response.json()) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized + + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + + 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.TelephonyCampaign].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return AsyncLROPoller[_models.TelephonyCampaign]( + self._client, raw_result, get_long_running_output, polling_method # type: ignore + ) + + @distributed_trace_async + async def get( + self, agent_name: str, campaign_name: str, *, operation_id: Optional[str] = None, **kwargs: Any + ) -> _models.TelephonyCampaign: + """Get a telephony campaign. + + Gets Campaign configuration and execution state without inline recipients. Absent or deleted + Campaigns return 404. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Immutable Campaign name. Required. + :type campaign_name: str + :keyword operation_id: Original response's Operation-Id guards its instance/round and survives + same-round actions. Replacement/name reuse: 409 campaign_operation_mismatch; + missing/expired/wrong-scope operation: 404. Default value is None. + :paramtype operation_id: str + :return: TelephonyCampaign. The TelephonyCampaign is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCampaign + :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.TelephonyCampaign] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_campaigns_get_request( + agent_name=agent_name, + campaign_name=campaign_name, + operation_id=operation_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyCampaign, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.TelephonyCampaignStatus]] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.TelephonyCampaign"]: + """List telephony campaigns. + + Lists the Agent's Campaigns without inline recipients. Filters are live views, not snapshots. + + :param agent_name: Owning Agent; never overridden in recipient inputs. 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: Opaque first_id for backward paging with unchanged scope/filters/order; + exclusive with after. Default value is None. + :paramtype before: str + :keyword status: Filter by Campaign business state. Known values are: "validating", "running", + "cancelling", "completed", "failed", "cancelled", and "deleting". Default value is None. + :paramtype status: str or ~azure.ai.projects.models.TelephonyCampaignStatus + :return: An iterator like instance of TelephonyCampaign + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCampaign]] = 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_voice_agents_campaigns_list_request( + agent_name=agent_name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + status=status, + 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.TelephonyCampaign], + 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) + + async def _cancel_initial( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> AsyncIterator[bytes]: + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError + 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_voice_agents_campaigns_cancel_request( + agent_name=agent_name, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_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 = True + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def begin_cancel( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Cancel a telephony campaign. + + Cancels a validating or running Campaign using If-Match. Stops new calls and retries; connected + calls finish naturally. Returns 202 with an operation monitor to track completion. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Campaign name. Required. + :type campaign_name: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key, generated if omitted. Original If-Match/key replays + 202 even after deletion/name reuse, never touching a replacement; conflicts return 409. Failed + cancellation needs a fresh key/current token. Default value is None. + :paramtype operation_id: str + :return: An instance of AsyncLROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.TelephonyCampaign] = 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._cancel_initial( + agent_name=agent_name, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + cls=lambda x, y, z: x, + headers=_headers, + params=_params, + **kwargs + ) + await raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) + + def get_long_running_output(pipeline_response): + response_headers = {} + response = pipeline_response.http_response + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + deserialized = _deserialize(_models.TelephonyCampaign, response.json()) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized + + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + + 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.TelephonyCampaign].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return AsyncLROPoller[_models.TelephonyCampaign]( + self._client, raw_result, get_long_running_output, polling_method # type: ignore + ) + + async def _delete_initial( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> AsyncIterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError 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.TelephonyCallJob] = 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[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_create_call_job_request( + _request = build_beta_voice_agents_campaigns_delete_request( agent_name=agent_name, - idempotency_key=idempotency_key, - content_type=content_type, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -19906,19 +21760,18 @@ async def create_call_job( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = True pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) 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 + if response.status_code not in [202, 204]: + 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, @@ -19927,14 +21780,15 @@ async def create_call_job( raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - response_headers["Retry-After"] = self._deserialize("duration-seconds-int", response.headers.get("Retry-After")) + if response.status_code == 202: + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + 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.TelephonyCallJob, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -19942,19 +21796,128 @@ async def create_call_job( return deserialized # type: ignore @distributed_trace_async - async def get_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) -> _models.TelephonyCallJob: - """Get an outbound telephony call job. + async def begin_delete( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> AsyncLROPoller[None]: + """Delete a telephony campaign. - Retrieves a durable direct or campaign-created outbound call job. + Deletes a terminal Campaign and its recipient/task data asynchronously. Returns bodyless 202 + with a monitor, not a tombstone; completion makes GET return 404 and lists omit it. Dataset, + connections, Agent, independent jobs and call history are preserved. - :param agent_name: Required. + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. :type agent_name: str - :param call_job_id: Required. - :type call_job_id: str - :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :param campaign_name: Immutable Campaign name. Required. + :type campaign_name: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key. Original If-Match/key replays 202 even after + deletion/name reuse, never touching a new instance; conflicts return 409. Failed cleanup needs + a fresh key/current token. Default value is None. + :paramtype operation_id: str + :return: An instance of AsyncLROPoller that returns None + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = 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._delete_initial( + agent_name=agent_name, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + cls=lambda x, y, z: x, + headers=_headers, + params=_params, + **kwargs + ) + await raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) + + def get_long_running_output(pipeline_response): # pylint: disable=inconsistent-return-statements + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + + 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[None].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return AsyncLROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore + + @distributed_trace + def list_validation_errors( + self, + agent_name: str, + campaign_name: str, + *, + limit: Optional[int] = None, + before: Optional[str] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.TelephonyCampaignValidationError"]: + """List campaign validation errors. + + Lists current-round row validation errors. Results may be partial during preparation; an empty + page does not establish success. Execution errors are in CallJobs; non-row failures are in + Campaign.error. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Campaign name. Deleting returns 409 campaign_deleting; absent/deleted + returns 404. Required. + :type campaign_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 before: Opaque first_id for backward paging with unchanged scope/filters/order; + exclusive with after. Default value is None. + :paramtype before: str + :keyword order: Sort invalid rows by their original row_number. Known values are: "asc" and + "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :return: An iterator like instance of TelephonyCampaignValidationError + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.TelephonyCampaignValidationError] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCampaignValidationError]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -19963,75 +21926,75 @@ async def get_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) - } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) + def prepare_request(_continuation_token=None): - _request = build_beta_voice_agents_telephony_get_call_job_request( - agent_name=agent_name, - call_job_id=call_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) + _request = build_beta_voice_agents_campaigns_list_validation_errors_request( + agent_name=agent_name, + campaign_name=campaign_name, + limit=limit, + after=_continuation_token, + before=before, + order=order, + 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.TelephonyCampaignValidationError], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) - response = pipeline_response.http_response + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return pipeline_response - return deserialized # type: ignore + return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def cancel_call_job( - self, agent_name: str, call_job_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any - ) -> _models.TelephonyCallJob: - """Cancel an outbound telephony call job. + async def get_operation( + self, agent_name: str, campaign_name: str, operation_id: str, **kwargs: Any + ) -> _models.TelephonyCampaignOperation: + """Get a campaign operation. - Requests cancellation of a durable outbound call job. A connected call is allowed to finish. + Gets the initiating operation's status. PUT/cancel pollers finish with a guarded Campaign GET; + deletion completes without a resource result. - :param agent_name: Required. + :param agent_name: Owning Agent. Required. :type agent_name: str - :param call_job_id: Required. - :type call_job_id: str - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :param campaign_name: Immutable Campaign name. Required. + :type campaign_name: str + :param operation_id: Operation-Id from the initiating response. Saved project/Agent + authorization still applies after resource deletion. Required. + :type operation_id: str + :return: TelephonyCampaignOperation. The TelephonyCampaignOperation is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCampaignOperation :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -20040,24 +22003,17 @@ async def cancel_call_job( 409: ResourceExistsError, 304: ResourceNotModifiedError, } - if match_condition == MatchConditions.IfNotModified: - error_map[412] = ResourceModifiedError - elif match_condition == MatchConditions.IfPresent: - error_map[412] = ResourceNotFoundError - elif match_condition == MatchConditions.IfMissing: - error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCampaignOperation] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_cancel_call_job_request( + _request = build_beta_voice_agents_campaigns_get_operation_request( agent_name=agent_name, - call_job_id=call_job_id, - etag=etag, - match_condition=match_condition, + campaign_name=campaign_name, + operation_id=operation_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -20075,7 +22031,7 @@ async def cancel_call_job( response = pipeline_response.http_response - if response.status_code not in [200, 202]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -20089,20 +22045,13 @@ async def cancel_call_job( raise HttpResponseError(response=response, model=error) response_headers = {} - if response.status_code == 200: - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - - if response.status_code == 202: - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - response_headers["Retry-After"] = self._deserialize( - "duration-seconds-int", response.headers.get("Retry-After") - ) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + deserialized = _deserialize(_models.TelephonyCampaignOperation, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # 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 2ca0414ab9ea..3a9607548c11 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 @@ -27,6 +27,16 @@ ConversationItem, ServerEvent, ) +from .._live import ( + AsyncBetaLive, + AsyncBetaLiveConnection, + AsyncBetaLiveConnectionManager, + LiveClientEvent, + LiveServerEvent, +) + +# Nested operation groups are re-exported here rather than in the generated package exports. +from ._patch_campaigns_async import BetaVoiceAgentsCampaignsOperations from ._operations import ( BetaEvaluationTaxonomiesOperations, BetaInsightsOperations, @@ -36,6 +46,7 @@ BetaSchedulesOperations, BetaSkillsOperations, BetaVoiceAgentsConversationsOperations, + BetaVoiceAgentsLiveConversationsOperations, BetaVoiceAgentsOperations as GeneratedBetaVoiceAgentsOperations, BetaVoiceAgentsTelephonyOperations, ) @@ -51,19 +62,29 @@ class BetaVoiceAgentsOperations(GeneratedBetaVoiceAgentsOperations): :attr:`~azure.ai.projects.aio.operations.BetaOperations.voice_agents` attribute. """ + campaigns: BetaVoiceAgentsCampaignsOperations + """:class:`~azure.ai.projects.aio.operations.BetaVoiceAgentsCampaignsOperations` operations""" conversations: BetaVoiceAgentsConversationsOperations """:class:`~azure.ai.projects.aio.operations.BetaVoiceAgentsConversationsOperations` operations""" + live_conversations: BetaVoiceAgentsLiveConversationsOperations + """:class:`~azure.ai.projects.aio.operations.BetaVoiceAgentsLiveConversationsOperations` operations""" telephony: BetaVoiceAgentsTelephonyOperations """:class:`~azure.ai.projects.aio.operations.BetaVoiceAgentsTelephonyOperations` operations""" realtime: AsyncBetaRealtime """:class:`~azure.ai.projects.aio.operations.AsyncBetaRealtime` operations""" + live: AsyncBetaLive + """:class:`~azure.ai.projects.aio.operations.AsyncBetaLive` operations""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.campaigns = BetaVoiceAgentsCampaignsOperations( + self._client, self._config, self._serialize, self._deserialize + ) # The generator does not emit realtime operations at all, since azure-core's HTTP # pipeline has no way to keep a WebSocket upgrade's resulting socket alive. Add our # hand-written client, which manages a real, long-lived connection, in its place. self.realtime = AsyncBetaRealtime(self) + self.live = AsyncBetaLive(self) class BetaOperations(GeneratedBetaOperations): @@ -127,6 +148,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "AsyncBetaRealtime", "AsyncBetaRealtimeConnection", "AsyncBetaRealtimeConnectionManager", + "AsyncBetaLive", + "AsyncBetaLiveConnection", + "AsyncBetaLiveConnectionManager", + "LiveClientEvent", + "LiveServerEvent", "BetaAgentInsightMonitorsOperations", "BetaAgentsOperations", "BetaEvaluationTaxonomiesOperations", @@ -138,7 +164,9 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "BetaRoutinesOperations", "BetaSchedulesOperations", "BetaSkillsOperations", + "BetaVoiceAgentsCampaignsOperations", "BetaVoiceAgentsConversationsOperations", + "BetaVoiceAgentsLiveConversationsOperations", "BetaVoiceAgentsOperations", "BetaVoiceAgentsTelephonyOperations", "ClientEvent", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_campaigns_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_campaigns_async.py new file mode 100644 index 000000000000..fa2176bedb12 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_campaigns_async.py @@ -0,0 +1,199 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Custom asynchronous Voice Agent campaign operations.""" + +from collections.abc import MutableMapping +from typing import Any, IO, Optional, Union, overload + +from azure.core import MatchConditions +from azure.core.polling import AsyncLROPoller + +from ._operations import BetaVoiceAgentsCampaignsOperations as GeneratedBetaVoiceAgentsCampaignsOperations +from ... import models as _models +from ..._utils.campaign_polling import _configure_campaign_polling + +JSON = MutableMapping[str, Any] + + +class BetaVoiceAgentsCampaignsOperations(GeneratedBetaVoiceAgentsCampaignsOperations): + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, access these operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s ``beta.voice_agents.campaigns`` attribute. + """ + + def _configure_polling(self, kwargs: dict[str, Any]) -> None: + _configure_campaign_polling( + kwargs, + self._config.polling_interval, + {"endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True)}, + is_async=True, + ) + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: _models.TelephonyCampaign, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> AsyncLROPoller[_models.TelephonyCampaign]: ... + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: JSON, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> AsyncLROPoller[_models.TelephonyCampaign]: ... + + @overload + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> AsyncLROPoller[_models.TelephonyCampaign]: ... + + async def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: Union[_models.TelephonyCampaign, JSON, IO[bytes]], + *, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + All recipients must validate and have CallJobs before dialing. Immediate calls may + begin before preparation finishes. The final Campaign GET is guarded by the initiating + operation ID. + + :param agent_name: Owning Agent. Required. + :type agent_name: str + :param campaign_name: Campaign name. Only failed preparation permits replacement. Required. + :type campaign_name: str + :param campaign: Complete campaign configuration. Required. + :type campaign: ~azure.ai.projects.models.TelephonyCampaign or MutableMapping[str, Any] or IO[bytes] + :keyword operation_id: Optional retry key. Conflicting reuse returns an error. + :paramtype operation_id: str + :keyword etag: Resource ETag used with ``match_condition``. + :paramtype etag: str + :keyword match_condition: The match condition to use with the ETag. + :paramtype match_condition: ~azure.core.MatchConditions + :return: A poller returning the Campaign after preparation. + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._configure_polling(kwargs) + return await super().begin_create( + agent_name, + campaign_name, + campaign, + operation_id=operation_id, + etag=etag, + match_condition=match_condition, + **kwargs, + ) + + async def begin_cancel( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any, + ) -> AsyncLROPoller[_models.TelephonyCampaign]: + """Cancel a validating or running telephony campaign. + + Stops new calls and retries; connected calls finish naturally. The final Campaign GET + is guarded by the initiating operation ID. + + :param agent_name: Owning Agent. Required. + :type agent_name: str + :param campaign_name: Campaign name. Required. + :type campaign_name: str + :keyword etag: Exact current Campaign ETag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use with the ETag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key. + :paramtype operation_id: str + :return: A poller returning the Campaign after cancellation. + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._configure_polling(kwargs) + return await super().begin_cancel( + agent_name, + campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + **kwargs, + ) + + async def begin_delete( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any, + ) -> AsyncLROPoller[None]: + """Delete a terminal telephony campaign and its recipient/task data. + + Completion does not fetch the deleted Campaign. Dataset, connections, Agent, + independent jobs, and call history are preserved. + + :param agent_name: Owning Agent. Required. + :type agent_name: str + :param campaign_name: Campaign name. Required. + :type campaign_name: str + :keyword etag: Exact current Campaign ETag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use with the ETag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key. + :paramtype operation_id: str + :return: A poller returning None after deletion. + :rtype: ~azure.core.polling.AsyncLROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._configure_polling(kwargs) + return await super().begin_delete( + agent_name, + campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + **kwargs, + ) 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 a170055a1338..718c0725ebb2 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 @@ -103,12 +103,18 @@ AgentTaxonomyInput, AgentVersionDetails, AgenticIdentityPreviewCredentials, + AnswerResource, + AnswerResourceChoice, + AnswerResourcePredicate, + AnswerResourceRefusal, + AnswerResourceScore, ApiError, ApiErrorResponse, ApiKeyCredentials, ApplyPatchToolParam, ApproximateLocation, ArtifactProfile, + AtTimeSchedule, AutoCodeInterpreterToolParam, AzureAIAgentTarget, AzureAIModelTarget, @@ -144,6 +150,7 @@ ChartCoordinate, ChatCompletionTool, ChatSummaryMemoryItem, + ChoiceProbabilityResource, ClusterInsightResult, ClusterTokenUsage, CodeBasedEvaluatorDefinition, @@ -166,11 +173,7 @@ CosmosDBIndex, CreateAsyncResponse, CreateSkillVersionFromFilesBody, - CreateTeamsPhoneExtensibilityTelephonyBindingRequest, - CreateTelephonyBindingRequest, - CreateTelephonyCallJobRequest, CreateTranscriptionResponseJsonUsage, - CreateTwilioTelephonyBindingRequest, CronTrigger, CustomCredential, CustomGrammarFormatParam, @@ -192,6 +195,7 @@ DatasetEvaluatorGenerationJobSource, DatasetReference, DatasetVersion, + DecisionResponse, DeleteAgentResponse, DeleteAgentVersionResponse, DeleteMemoryResult, @@ -247,6 +251,7 @@ FileDatasetVersion, FileSearchTool, FileSearchToolboxTool, + FixedIntervalRetryPolicy, FixedRatioVersionSelectionRule, FolderDatasetVersion, FoundryModelWarning, @@ -271,9 +276,12 @@ HybridSearchOptions, ImageGenTool, ImageGenToolInputImageMask, + ImmediateSchedule, Index, InlineSkillParam, InlineSkillSourceParam, + InlineVoiceSubagent, + InputTokensDetailsResource, Insight, InsightCluster, InsightModelConfiguration, @@ -289,6 +297,147 @@ InvokeAgentInvocationsApiRoutineAction, InvokeAgentResponsesApiDispatchPayload, InvokeAgentResponsesApiRoutineAction, + LiveAllowedServerEventParam, + LiveAllowedToolsChoiceParam, + LiveApplyPatchToolInputParam, + LiveAudioFormat, + LiveClientConfigParam, + LiveClientEvent, + LiveClientEventLiveCommentaryAppendParam, + LiveClientEventLiveDecisionCreateParam, + LiveClientEventLiveDecisionItemCreateParam, + LiveClientEventLiveDecisionItemDeleteParam, + LiveClientEventLiveInputAudioAppendEvent, + LiveClientEventLiveInputAudioMuteParam, + LiveClientEventLiveInputAudioUnmuteParam, + LiveClientEventLiveInstructionsAppendParam, + LiveClientEventLiveOutputAudioFixturePlayParam, + LiveClientEventLiveResponseCreateParam, + LiveClientEventLiveResponseItemCreateParam, + LiveClientEventLiveSessionCloseParam, + LiveClientEventLiveSessionUpdateParam, + LiveClientEventLiveThinkingAppendParam, + LiveCodeInterpreterToolInputParam, + LiveComputerToolInputParam, + LiveContainerNetworkPolicyDisabledParam, + LiveContainerReferenceParam, + LiveContextWindowUsage, + LiveCustomToolInputParam, + LiveCustomVoiceParam, + LiveDataChannelConfigParam, + LiveDecisionChoiceParam, + LiveDecisionChoiceQuestionParam, + LiveDecisionCompleted, + LiveDecisionCustomToolCallOutputParam, + LiveDecisionCustomToolCallParam, + LiveDecisionFunctionCallOutputParam, + LiveDecisionFunctionCallParam, + LiveDecisionInputImageParam, + LiveDecisionInputItemParam, + LiveDecisionInputItemParamMessage, + LiveDecisionInputJsonParam, + LiveDecisionInputTextParam, + LiveDecisionJsonObject, + LiveDecisionPredicateQuestionParam, + LiveDecisionQuestion, + LiveDecisionQuestionsInputParam, + LiveDecisionScoreLevelParam, + LiveDecisionScoreQuestionParam, + LiveDecisionStoredCustomToolCallOutputParam, + LiveDecisionStoredCustomToolCallParam, + LiveDecisionStoredFunctionCallOutputParam, + LiveDecisionStoredFunctionCallParam, + LiveDecisionStoredInputItemParam, + LiveDecisionStoredInputItemParamMessage, + LiveDecisionTriggerInputParam, + LiveDecisionsDelegationUpdateParam, + LiveDecisionsSettingsInputParam, + LiveDecisionsSettingsUpdateParam, + LiveDelegationReasoningInputParam, + LiveDelegationTextInputParam, + LiveFileSearchToolInputParam, + LiveFunctionToolChoiceParam, + LiveFunctionToolInputParam, + LiveHostedShellContainerAutoParam, + LiveHostedShellNetworkPolicyAllowlistParam, + LiveHostedShellToolInputParam, + LiveImageGenerationToolInputParam, + LiveInitialAssistantMessageItemParam, + LiveInitialDeveloperMessageItemParam, + LiveInitialInputTextContentPartParam, + LiveInitialItem, + LiveInitialOutputTextContentPartParam, + LiveInitialSessionAudioOutputParam, + LiveInitialSessionAudioParam, + LiveInitialTextContentPartParam, + LiveInitialUserMessageItemParam, + LiveInlineSkillParam, + LiveInlineSkillSourceParam, + LiveInputAudioAppend, + LiveLiveError, + LiveLocalEnvironmentParam, + LiveLocalSkillParam, + LiveMCPToolChoiceParam, + LiveMCPToolInputParam, + LiveNamespaceToolInputParam, + LiveOutputAudioDelta, + LiveProgrammaticToolInputParam, + LiveResponsesDelegationSettingsInputParam, + LiveResponsesDelegationSettingsUpdateInputParam, + LiveResponsesDelegationUpdateParam, + LiveServerEvent, + LiveServerEventLiveCommentaryAppended, + LiveServerEventLiveDecisionEvent, + LiveServerEventLiveDecisionItemCreated, + LiveServerEventLiveDecisionItemDeleted, + LiveServerEventLiveDelegationCreated, + LiveServerEventLiveErrorEvent, + LiveServerEventLiveInfoEvent, + LiveServerEventLiveInputAudioMuted, + LiveServerEventLiveInputAudioUnmuted, + LiveServerEventLiveInputTranscriptDelta, + LiveServerEventLiveInstructionsAppended, + LiveServerEventLiveOutputAudioFixturePlayed, + LiveServerEventLiveOutputAudioFixturePlaying, + LiveServerEventLiveOutputTranscriptDelta, + LiveServerEventLiveResponseEvent, + LiveServerEventLiveSessionClosed, + LiveServerEventLiveSessionStarted, + LiveServerEventLiveSessionUpdated, + LiveServerEventLiveSessionUsageUpdated, + LiveServerEventLiveThinkingAppended, + LiveServerEventLiveTransportAnswered, + LiveServerEventLiveTransportDtmfReceived, + LiveServerEventLiveTransportDtmfSent, + LiveServerEventLiveTransportFailed, + LiveServerEventLiveTransportRinging, + LiveSessionAudioFormatPCMAParam, + LiveSessionAudioFormatPCMParam, + LiveSessionAudioFormatPCMUParam, + LiveSessionCreateParams, + LiveSessionCreateParamsDelegation, + LiveSessionCreateParamsDelegationLiveClientDelegationParam, + LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam, + LiveSessionCreateParamsDelegationLiveResponsesDelegationParam, + LiveSessionStartEvent, + LiveSessionUpdateParams, + LiveSessionUpdateParamsDelegation, + LiveSessionUpdateParamsDelegationLiveClientDelegationParam, + LiveSessionUsage, + LiveSkillReferenceParam, + LiveSpecificApplyPatchParam, + LiveSpecificCodeInterpreterParam, + LiveSpecificComputerParam, + LiveSpecificCustomToolParam, + LiveSpecificFileSearchParam, + LiveSpecificFunctionShellParam, + LiveSpecificImageGenParam, + LiveSpecificProgrammaticToolCallingParam, + LiveSpecificWebSearchParam, + LiveSpecificWebSearchPreviewParam, + LiveToolSearchToolInputParam, + LiveTransportCallError, + LiveWebSearchToolInputParam, LocalShellToolParam, LocalSkillParam, LogProbProperties, @@ -352,9 +501,11 @@ OpenApiToolboxTool, OptimizationContext, OtlpTelemetryEndpoint, - PSTNTelephonyTransferDestination, + OutputTokensDetailsResource, PendingUploadRequest, PendingUploadResponse, + PerRecipientSchedule, + PhoneNumber, PickPropertiesVoiceAgentAudioConfig, ProceduralMemoryItem, ProgrammaticToolCallingParam, @@ -406,6 +557,18 @@ RealtimeMCPToolCall, RealtimeMCPToolExecutionError, RealtimeReasoning, + RealtimeResponseInputAudio, + RealtimeResponseInputFunctionCall, + RealtimeResponseInputFunctionCallOutput, + RealtimeResponseInputImage, + RealtimeResponseInputMessage, + RealtimeResponseInputMessageAssistant, + RealtimeResponseInputMessageAssistantContent, + RealtimeResponseInputMessageDeveloper, + RealtimeResponseInputMessageSystem, + RealtimeResponseInputMessageUser, + RealtimeResponseInputText, + RealtimeResponseItemReference, RealtimeResponseStatusDetails, RealtimeResponseStatusDetailsError, RealtimeResponseUsage, @@ -471,6 +634,7 @@ ReminderPreviewToolboxTool, ResponseUsageInputTokensDetails, ResponseUsageOutputTokensDetails, + ResponseUsageResource, ResponsesProtocolConfiguration, Routine, RoutineAction, @@ -485,6 +649,7 @@ ScheduleRoutineTrigger, ScheduleRun, ScheduleTask, + ScoreProbabilityResource, SessionConfiguration, SessionDirectoryEntry, SessionFileWriteResult, @@ -494,7 +659,9 @@ ShellToolboxTool, SimpleQnADataGenerationJobConfiguration, SimulationSeedDataGenerationJobConfiguration, - SipTelephonyTransferDestination, + SipAddress, + SipTelephonyBinding, + SipTelephonyBindingListItem, SkillDetails, SkillInlineContent, SkillReference, @@ -511,26 +678,32 @@ SupervisedFineTuningDataGenerationJobOutputConfiguration, TaxonomyCategory, TaxonomySubCategory, + TeamsAddress, TeamsPhoneExtensibilityTelephonyBinding, TeamsPhoneExtensibilityTelephonyBindingListItem, - TeamsTelephonyTransferDestination, TelemetryConfig, TelemetryEndpoint, TelemetryEndpointAuth, + TelephonyAddress, TelephonyBinding, TelephonyBindingListItem, TelephonyCallJob, TelephonyCallJobCancellation, + TelephonyCallJobCreate, TelephonyCallJobSchedule, TelephonyCallLifecycleEvent, TelephonyCallRecord, TelephonyCallSummary, TelephonyCallTiming, TelephonyCallTrace, - TelephonyOutboundDestination, - TelephonyOutboundFixedIntervalRetryPolicy, + TelephonyCampaign, + TelephonyCampaignDatasetReference, + TelephonyCampaignOperation, + TelephonyCampaignProgress, + TelephonyCampaignSchedule, + TelephonyCampaignValidationError, TelephonyOutboundRetryPolicy, - TelephonyTransferDestination, + TelephonyRecipient, TelephonyTransferTarget, TelephonyTransferTargets, TextResponseFormat, @@ -609,25 +782,68 @@ VoiceAgentAzureSemanticVadEnTurnDetection, VoiceAgentAzureSemanticVadMultilingualTurnDetection, VoiceAgentAzureSemanticVadTurnDetection, + VoiceAgentBaseDefinition, VoiceAgentClientEventRtcCallSdpCreate, VoiceAgentClientEventSessionAvatarConnect, VoiceAgentClientEventSessionUpdate, + VoiceAgentCollectDtmfStartArguments, + VoiceAgentCollectDtmfSystemTool, + VoiceAgentCollectSmsStartArguments, + VoiceAgentCollectSmsSystemTool, + VoiceAgentCollectionStartArguments, VoiceAgentDefinition, + VoiceAgentDelegateSubagentConfig, + VoiceAgentDigitRecognitionSystemTool, + VoiceAgentDtmfFixedLengthCompletionMode, + VoiceAgentDtmfInterDigitSilenceCompletionMode, + VoiceAgentDtmfTerminatorCompletionMode, VoiceAgentEchoCancellation, VoiceAgentEndConversationSystemTool, VoiceAgentEndOfUtteranceDetection, + VoiceAgentEventGridPostCallDestination, VoiceAgentFunctionTool, VoiceAgentGreetingConfig, + VoiceAgentHandoffCondition, + VoiceAgentHandoffEdgeState, + VoiceAgentHandoffNodeState, + VoiceAgentHandoffPolicy, + VoiceAgentHandoffState, + VoiceAgentHandoffVoiceAdaptation, + VoiceAgentInlineSubagentConfig, VoiceAgentInputTranscription, VoiceAgentInterimResponseConfig, + VoiceAgentLanguageDetectionArguments, + VoiceAgentLanguageDetectionSystemTool, + VoiceAgentLiveClientDelegation, + VoiceAgentLiveClientDelegationConversationItem, + VoiceAgentLiveConversation, + VoiceAgentLiveConversationItem, + VoiceAgentLiveDefinition, + VoiceAgentLiveDelegation, + VoiceAgentLiveDelegationConversationItem, + VoiceAgentLiveDelegationItem, + VoiceAgentLiveDelegationResultItem, + VoiceAgentLiveFoundryManagedAgentDelegationItem, + VoiceAgentLiveInputConversationItem, + VoiceAgentLiveManagedAgentDelegation, + VoiceAgentLiveOutputConversationItem, + VoiceAgentLiveResponsesDelegation, + VoiceAgentLiveResponsesDelegationConversationItem, + VoiceAgentLiveSessionResource, VoiceAgentLlmGeneratedGreetingConfig, VoiceAgentLlmInterimResponseConfig, VoiceAgentMcpTool, VoiceAgentNoiseReduction, + VoiceAgentPostCallConfig, + VoiceAgentPostCallDestination, VoiceAgentRealtimeResponse, VoiceAgentResponseCreateParams, + VoiceAgentRoutinePostCallDestination, VoiceAgentRtcCallErrorDetails, VoiceAgentSemanticVadTurnDetection, + VoiceAgentSendDtmfSystemTool, + VoiceAgentSendSmsSystemTool, + VoiceAgentServerEventInputCollectionStatus, VoiceAgentServerEventResponseAnimationBlendshapesDelta, VoiceAgentServerEventResponseAnimationBlendshapesDone, VoiceAgentServerEventResponseAnimationVisemeDelta, @@ -640,9 +856,14 @@ VoiceAgentServerEventSessionAvatarConnecting, VoiceAgentServerEventSessionAvatarSwitchToIdle, VoiceAgentServerEventSessionAvatarSwitchToSpeaking, + VoiceAgentServerEventSessionHandoffAborted, + VoiceAgentServerEventSessionHandoffCompleted, + VoiceAgentServerEventSessionHandoffStarted, VoiceAgentServerEventSessionSubagentAborted, VoiceAgentServerEventSessionSubagentCompleted, VoiceAgentServerEventSessionSubagentStarted, + VoiceAgentServerEventSystemToolArgumentsDelta, + VoiceAgentServerEventSystemToolArgumentsDone, VoiceAgentServerEventWarning, VoiceAgentServerEventWarningDetails, VoiceAgentServerVadTurnDetection, @@ -658,12 +879,18 @@ VoiceAgentSubagentConfig, VoiceAgentSubagentResponsePolicy, VoiceAgentSystemTool, + VoiceAgentSystemToolItem, VoiceAgentTemplateGreetingConfig, VoiceAgentTool, VoiceAgentToolboxTool, VoiceAgentTranscriptionPhrase, VoiceAgentTranscriptionWord, + VoiceAgentTransferDestination, + VoiceAgentTransferRouting, + VoiceAgentTransferSystemTool, + VoiceAgentTransferTarget, VoiceAgentTurnDetectionConfig, + VoiceAgentVoiceConfig, VoiceAudioItem, VoiceConversation, VoiceConversationEngine, @@ -716,6 +943,7 @@ AgentState, AgentStateSource, AgentVersionStatus, + AnswerResourceType, AttackStrategy, AzureAISearchQueryType, CallableToolAllowedCaller, @@ -762,6 +990,25 @@ InputFidelity, InsightType, JobStatus, + LiveAudioFormatType, + LiveClientEventType, + LiveContainerMemoryLimit, + LiveDecisionInputItemParamType, + LiveDecisionQuestionType, + LiveDecisionStoredInputItemParamType, + LiveDetailEnum, + LiveFunctionCallItemStatus, + LiveInitialItemType, + LiveInitialMessageStatus, + LiveReasoningEffort, + LiveReasoningSummary, + LiveResponsesServiceTier, + LiveServerEventType, + LiveSessionCreateParamsDelegationType, + LiveSessionUpdateParamsDelegationType, + LiveTextVerbosity, + LiveToolChoiceEnum, + LiveToolChoiceValueEnum, MemoryItemKind, MemoryOperationKind, MemoryStoreKind, @@ -770,6 +1017,7 @@ Microsoft365PublishScope, MicrosoftCopilotBuiltInTool, MisalignmentErrorType, + ModelIdsLive, OpenApiAuthType, OperationState, OptimizationContextType, @@ -785,6 +1033,7 @@ RealtimeConversationItemType, RealtimeMcpErrorType, RealtimeReasoningEffort, + RealtimeResponseInputMessageType, RealtimeServerEventType, ReasoningEffort, ReasoningModeEnum, @@ -811,7 +1060,7 @@ TelemetryEndpointAuthType, TelemetryEndpointKind, TelemetryTransportProtocol, - TelephonyBindingStatus, + TelephonyAddressType, TelephonyCallDurationBasis, TelephonyCallEndReason, TelephonyCallJobStatus, @@ -825,10 +1074,11 @@ TelephonyCallTimestampSource, TelephonyCallTraceMode, TelephonyCallTraceStatus, - TelephonyOutboundDestinationType, + TelephonyCampaignOperationKind, + TelephonyCampaignScheduleType, + TelephonyCampaignStatus, TelephonyOutboundRetryPolicyType, TelephonyProvider, - TelephonyTransferDestinationKind, TextResponseFormatConfigurationType, ToolChoiceOptions, ToolChoiceParamType, @@ -844,23 +1094,49 @@ VoiceAgentAudioTimestampType, VoiceAgentAvatarOutputProtocol, VoiceAgentAvatarType, + VoiceAgentClientEventTypeExtension, + VoiceAgentConversationItemTypeExtension, + VoiceAgentDtmfTerminator, VoiceAgentEchoCancellationReferenceSource, VoiceAgentEndOfUtteranceDetectionModel, VoiceAgentEndOfUtteranceThresholdLevel, + VoiceAgentGreetingMode, + VoiceAgentHandoffAbortReason, + VoiceAgentHandoffPipelineFamily, + VoiceAgentHandoffReasoningEffort, + VoiceAgentHandoffTargetResponse, + VoiceAgentInputCollectionChannel, + VoiceAgentInputCollectionStatus, VoiceAgentInputTranscriptionModel, VoiceAgentInterimResponseTrigger, + VoiceAgentInterimResponseType, + VoiceAgentLiveConversationItemType, + VoiceAgentLiveDelegationStatus, + VoiceAgentLiveDelegationTarget, + VoiceAgentLiveDelegationType, VoiceAgentNoiseReductionType, + VoiceAgentPostCallDestinationType, + VoiceAgentPostCallIncludeOption, VoiceAgentProfanityFilterMode, + VoiceAgentRtcCallErrorType, + VoiceAgentServerEventTypeExtension, VoiceAgentSessionIncludeOption, VoiceAgentSoundscapeSound, + VoiceAgentSubProtocol, VoiceAgentSubagentAbortReason, + VoiceAgentSubagentType, + VoiceAgentSystemToolItemStatus, VoiceAgentSystemToolName, VoiceAgentToolResponseScheduling, + VoiceAgentToolType, + VoiceAgentTransferDestinationType, + VoiceAgentTransferStrategy, VoiceAgentTransport, VoiceAgentTurnDetectionType, VoiceAudioCodec, VoiceAudioContainerFormat, VoiceAudioRole, + VoiceConversationEngineType, VoiceConversationStatus, VoiceModelType, VoiceOutputModality, @@ -959,12 +1235,18 @@ "AgentTaxonomyInput", "AgentVersionDetails", "AgenticIdentityPreviewCredentials", + "AnswerResource", + "AnswerResourceChoice", + "AnswerResourcePredicate", + "AnswerResourceRefusal", + "AnswerResourceScore", "ApiError", "ApiErrorResponse", "ApiKeyCredentials", "ApplyPatchToolParam", "ApproximateLocation", "ArtifactProfile", + "AtTimeSchedule", "AutoCodeInterpreterToolParam", "AzureAIAgentTarget", "AzureAIModelTarget", @@ -1000,6 +1282,7 @@ "ChartCoordinate", "ChatCompletionTool", "ChatSummaryMemoryItem", + "ChoiceProbabilityResource", "ClusterInsightResult", "ClusterTokenUsage", "CodeBasedEvaluatorDefinition", @@ -1022,11 +1305,7 @@ "CosmosDBIndex", "CreateAsyncResponse", "CreateSkillVersionFromFilesBody", - "CreateTeamsPhoneExtensibilityTelephonyBindingRequest", - "CreateTelephonyBindingRequest", - "CreateTelephonyCallJobRequest", "CreateTranscriptionResponseJsonUsage", - "CreateTwilioTelephonyBindingRequest", "CronTrigger", "CustomCredential", "CustomGrammarFormatParam", @@ -1048,6 +1327,7 @@ "DatasetEvaluatorGenerationJobSource", "DatasetReference", "DatasetVersion", + "DecisionResponse", "DeleteAgentResponse", "DeleteAgentVersionResponse", "DeleteMemoryResult", @@ -1103,6 +1383,7 @@ "FileDatasetVersion", "FileSearchTool", "FileSearchToolboxTool", + "FixedIntervalRetryPolicy", "FixedRatioVersionSelectionRule", "FolderDatasetVersion", "FoundryModelWarning", @@ -1127,9 +1408,12 @@ "HybridSearchOptions", "ImageGenTool", "ImageGenToolInputImageMask", + "ImmediateSchedule", "Index", "InlineSkillParam", "InlineSkillSourceParam", + "InlineVoiceSubagent", + "InputTokensDetailsResource", "Insight", "InsightCluster", "InsightModelConfiguration", @@ -1145,6 +1429,147 @@ "InvokeAgentInvocationsApiRoutineAction", "InvokeAgentResponsesApiDispatchPayload", "InvokeAgentResponsesApiRoutineAction", + "LiveAllowedServerEventParam", + "LiveAllowedToolsChoiceParam", + "LiveApplyPatchToolInputParam", + "LiveAudioFormat", + "LiveClientConfigParam", + "LiveClientEvent", + "LiveClientEventLiveCommentaryAppendParam", + "LiveClientEventLiveDecisionCreateParam", + "LiveClientEventLiveDecisionItemCreateParam", + "LiveClientEventLiveDecisionItemDeleteParam", + "LiveClientEventLiveInputAudioAppendEvent", + "LiveClientEventLiveInputAudioMuteParam", + "LiveClientEventLiveInputAudioUnmuteParam", + "LiveClientEventLiveInstructionsAppendParam", + "LiveClientEventLiveOutputAudioFixturePlayParam", + "LiveClientEventLiveResponseCreateParam", + "LiveClientEventLiveResponseItemCreateParam", + "LiveClientEventLiveSessionCloseParam", + "LiveClientEventLiveSessionUpdateParam", + "LiveClientEventLiveThinkingAppendParam", + "LiveCodeInterpreterToolInputParam", + "LiveComputerToolInputParam", + "LiveContainerNetworkPolicyDisabledParam", + "LiveContainerReferenceParam", + "LiveContextWindowUsage", + "LiveCustomToolInputParam", + "LiveCustomVoiceParam", + "LiveDataChannelConfigParam", + "LiveDecisionChoiceParam", + "LiveDecisionChoiceQuestionParam", + "LiveDecisionCompleted", + "LiveDecisionCustomToolCallOutputParam", + "LiveDecisionCustomToolCallParam", + "LiveDecisionFunctionCallOutputParam", + "LiveDecisionFunctionCallParam", + "LiveDecisionInputImageParam", + "LiveDecisionInputItemParam", + "LiveDecisionInputItemParamMessage", + "LiveDecisionInputJsonParam", + "LiveDecisionInputTextParam", + "LiveDecisionJsonObject", + "LiveDecisionPredicateQuestionParam", + "LiveDecisionQuestion", + "LiveDecisionQuestionsInputParam", + "LiveDecisionScoreLevelParam", + "LiveDecisionScoreQuestionParam", + "LiveDecisionStoredCustomToolCallOutputParam", + "LiveDecisionStoredCustomToolCallParam", + "LiveDecisionStoredFunctionCallOutputParam", + "LiveDecisionStoredFunctionCallParam", + "LiveDecisionStoredInputItemParam", + "LiveDecisionStoredInputItemParamMessage", + "LiveDecisionTriggerInputParam", + "LiveDecisionsDelegationUpdateParam", + "LiveDecisionsSettingsInputParam", + "LiveDecisionsSettingsUpdateParam", + "LiveDelegationReasoningInputParam", + "LiveDelegationTextInputParam", + "LiveFileSearchToolInputParam", + "LiveFunctionToolChoiceParam", + "LiveFunctionToolInputParam", + "LiveHostedShellContainerAutoParam", + "LiveHostedShellNetworkPolicyAllowlistParam", + "LiveHostedShellToolInputParam", + "LiveImageGenerationToolInputParam", + "LiveInitialAssistantMessageItemParam", + "LiveInitialDeveloperMessageItemParam", + "LiveInitialInputTextContentPartParam", + "LiveInitialItem", + "LiveInitialOutputTextContentPartParam", + "LiveInitialSessionAudioOutputParam", + "LiveInitialSessionAudioParam", + "LiveInitialTextContentPartParam", + "LiveInitialUserMessageItemParam", + "LiveInlineSkillParam", + "LiveInlineSkillSourceParam", + "LiveInputAudioAppend", + "LiveLiveError", + "LiveLocalEnvironmentParam", + "LiveLocalSkillParam", + "LiveMCPToolChoiceParam", + "LiveMCPToolInputParam", + "LiveNamespaceToolInputParam", + "LiveOutputAudioDelta", + "LiveProgrammaticToolInputParam", + "LiveResponsesDelegationSettingsInputParam", + "LiveResponsesDelegationSettingsUpdateInputParam", + "LiveResponsesDelegationUpdateParam", + "LiveServerEvent", + "LiveServerEventLiveCommentaryAppended", + "LiveServerEventLiveDecisionEvent", + "LiveServerEventLiveDecisionItemCreated", + "LiveServerEventLiveDecisionItemDeleted", + "LiveServerEventLiveDelegationCreated", + "LiveServerEventLiveErrorEvent", + "LiveServerEventLiveInfoEvent", + "LiveServerEventLiveInputAudioMuted", + "LiveServerEventLiveInputAudioUnmuted", + "LiveServerEventLiveInputTranscriptDelta", + "LiveServerEventLiveInstructionsAppended", + "LiveServerEventLiveOutputAudioFixturePlayed", + "LiveServerEventLiveOutputAudioFixturePlaying", + "LiveServerEventLiveOutputTranscriptDelta", + "LiveServerEventLiveResponseEvent", + "LiveServerEventLiveSessionClosed", + "LiveServerEventLiveSessionStarted", + "LiveServerEventLiveSessionUpdated", + "LiveServerEventLiveSessionUsageUpdated", + "LiveServerEventLiveThinkingAppended", + "LiveServerEventLiveTransportAnswered", + "LiveServerEventLiveTransportDtmfReceived", + "LiveServerEventLiveTransportDtmfSent", + "LiveServerEventLiveTransportFailed", + "LiveServerEventLiveTransportRinging", + "LiveSessionAudioFormatPCMAParam", + "LiveSessionAudioFormatPCMParam", + "LiveSessionAudioFormatPCMUParam", + "LiveSessionCreateParams", + "LiveSessionCreateParamsDelegation", + "LiveSessionCreateParamsDelegationLiveClientDelegationParam", + "LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam", + "LiveSessionCreateParamsDelegationLiveResponsesDelegationParam", + "LiveSessionStartEvent", + "LiveSessionUpdateParams", + "LiveSessionUpdateParamsDelegation", + "LiveSessionUpdateParamsDelegationLiveClientDelegationParam", + "LiveSessionUsage", + "LiveSkillReferenceParam", + "LiveSpecificApplyPatchParam", + "LiveSpecificCodeInterpreterParam", + "LiveSpecificComputerParam", + "LiveSpecificCustomToolParam", + "LiveSpecificFileSearchParam", + "LiveSpecificFunctionShellParam", + "LiveSpecificImageGenParam", + "LiveSpecificProgrammaticToolCallingParam", + "LiveSpecificWebSearchParam", + "LiveSpecificWebSearchPreviewParam", + "LiveToolSearchToolInputParam", + "LiveTransportCallError", + "LiveWebSearchToolInputParam", "LocalShellToolParam", "LocalSkillParam", "LogProbProperties", @@ -1208,9 +1633,11 @@ "OpenApiToolboxTool", "OptimizationContext", "OtlpTelemetryEndpoint", - "PSTNTelephonyTransferDestination", + "OutputTokensDetailsResource", "PendingUploadRequest", "PendingUploadResponse", + "PerRecipientSchedule", + "PhoneNumber", "PickPropertiesVoiceAgentAudioConfig", "ProceduralMemoryItem", "ProgrammaticToolCallingParam", @@ -1262,6 +1689,18 @@ "RealtimeMCPToolCall", "RealtimeMCPToolExecutionError", "RealtimeReasoning", + "RealtimeResponseInputAudio", + "RealtimeResponseInputFunctionCall", + "RealtimeResponseInputFunctionCallOutput", + "RealtimeResponseInputImage", + "RealtimeResponseInputMessage", + "RealtimeResponseInputMessageAssistant", + "RealtimeResponseInputMessageAssistantContent", + "RealtimeResponseInputMessageDeveloper", + "RealtimeResponseInputMessageSystem", + "RealtimeResponseInputMessageUser", + "RealtimeResponseInputText", + "RealtimeResponseItemReference", "RealtimeResponseStatusDetails", "RealtimeResponseStatusDetailsError", "RealtimeResponseUsage", @@ -1327,6 +1766,7 @@ "ReminderPreviewToolboxTool", "ResponseUsageInputTokensDetails", "ResponseUsageOutputTokensDetails", + "ResponseUsageResource", "ResponsesProtocolConfiguration", "Routine", "RoutineAction", @@ -1341,6 +1781,7 @@ "ScheduleRoutineTrigger", "ScheduleRun", "ScheduleTask", + "ScoreProbabilityResource", "SessionConfiguration", "SessionDirectoryEntry", "SessionFileWriteResult", @@ -1350,7 +1791,9 @@ "ShellToolboxTool", "SimpleQnADataGenerationJobConfiguration", "SimulationSeedDataGenerationJobConfiguration", - "SipTelephonyTransferDestination", + "SipAddress", + "SipTelephonyBinding", + "SipTelephonyBindingListItem", "SkillDetails", "SkillInlineContent", "SkillReference", @@ -1367,26 +1810,32 @@ "SupervisedFineTuningDataGenerationJobOutputConfiguration", "TaxonomyCategory", "TaxonomySubCategory", + "TeamsAddress", "TeamsPhoneExtensibilityTelephonyBinding", "TeamsPhoneExtensibilityTelephonyBindingListItem", - "TeamsTelephonyTransferDestination", "TelemetryConfig", "TelemetryEndpoint", "TelemetryEndpointAuth", + "TelephonyAddress", "TelephonyBinding", "TelephonyBindingListItem", "TelephonyCallJob", "TelephonyCallJobCancellation", + "TelephonyCallJobCreate", "TelephonyCallJobSchedule", "TelephonyCallLifecycleEvent", "TelephonyCallRecord", "TelephonyCallSummary", "TelephonyCallTiming", "TelephonyCallTrace", - "TelephonyOutboundDestination", - "TelephonyOutboundFixedIntervalRetryPolicy", + "TelephonyCampaign", + "TelephonyCampaignDatasetReference", + "TelephonyCampaignOperation", + "TelephonyCampaignProgress", + "TelephonyCampaignSchedule", + "TelephonyCampaignValidationError", "TelephonyOutboundRetryPolicy", - "TelephonyTransferDestination", + "TelephonyRecipient", "TelephonyTransferTarget", "TelephonyTransferTargets", "TextResponseFormat", @@ -1465,25 +1914,68 @@ "VoiceAgentAzureSemanticVadEnTurnDetection", "VoiceAgentAzureSemanticVadMultilingualTurnDetection", "VoiceAgentAzureSemanticVadTurnDetection", + "VoiceAgentBaseDefinition", "VoiceAgentClientEventRtcCallSdpCreate", "VoiceAgentClientEventSessionAvatarConnect", "VoiceAgentClientEventSessionUpdate", + "VoiceAgentCollectDtmfStartArguments", + "VoiceAgentCollectDtmfSystemTool", + "VoiceAgentCollectSmsStartArguments", + "VoiceAgentCollectSmsSystemTool", + "VoiceAgentCollectionStartArguments", "VoiceAgentDefinition", + "VoiceAgentDelegateSubagentConfig", + "VoiceAgentDigitRecognitionSystemTool", + "VoiceAgentDtmfFixedLengthCompletionMode", + "VoiceAgentDtmfInterDigitSilenceCompletionMode", + "VoiceAgentDtmfTerminatorCompletionMode", "VoiceAgentEchoCancellation", "VoiceAgentEndConversationSystemTool", "VoiceAgentEndOfUtteranceDetection", + "VoiceAgentEventGridPostCallDestination", "VoiceAgentFunctionTool", "VoiceAgentGreetingConfig", + "VoiceAgentHandoffCondition", + "VoiceAgentHandoffEdgeState", + "VoiceAgentHandoffNodeState", + "VoiceAgentHandoffPolicy", + "VoiceAgentHandoffState", + "VoiceAgentHandoffVoiceAdaptation", + "VoiceAgentInlineSubagentConfig", "VoiceAgentInputTranscription", "VoiceAgentInterimResponseConfig", + "VoiceAgentLanguageDetectionArguments", + "VoiceAgentLanguageDetectionSystemTool", + "VoiceAgentLiveClientDelegation", + "VoiceAgentLiveClientDelegationConversationItem", + "VoiceAgentLiveConversation", + "VoiceAgentLiveConversationItem", + "VoiceAgentLiveDefinition", + "VoiceAgentLiveDelegation", + "VoiceAgentLiveDelegationConversationItem", + "VoiceAgentLiveDelegationItem", + "VoiceAgentLiveDelegationResultItem", + "VoiceAgentLiveFoundryManagedAgentDelegationItem", + "VoiceAgentLiveInputConversationItem", + "VoiceAgentLiveManagedAgentDelegation", + "VoiceAgentLiveOutputConversationItem", + "VoiceAgentLiveResponsesDelegation", + "VoiceAgentLiveResponsesDelegationConversationItem", + "VoiceAgentLiveSessionResource", "VoiceAgentLlmGeneratedGreetingConfig", "VoiceAgentLlmInterimResponseConfig", "VoiceAgentMcpTool", "VoiceAgentNoiseReduction", + "VoiceAgentPostCallConfig", + "VoiceAgentPostCallDestination", "VoiceAgentRealtimeResponse", "VoiceAgentResponseCreateParams", + "VoiceAgentRoutinePostCallDestination", "VoiceAgentRtcCallErrorDetails", "VoiceAgentSemanticVadTurnDetection", + "VoiceAgentSendDtmfSystemTool", + "VoiceAgentSendSmsSystemTool", + "VoiceAgentServerEventInputCollectionStatus", "VoiceAgentServerEventResponseAnimationBlendshapesDelta", "VoiceAgentServerEventResponseAnimationBlendshapesDone", "VoiceAgentServerEventResponseAnimationVisemeDelta", @@ -1496,9 +1988,14 @@ "VoiceAgentServerEventSessionAvatarConnecting", "VoiceAgentServerEventSessionAvatarSwitchToIdle", "VoiceAgentServerEventSessionAvatarSwitchToSpeaking", + "VoiceAgentServerEventSessionHandoffAborted", + "VoiceAgentServerEventSessionHandoffCompleted", + "VoiceAgentServerEventSessionHandoffStarted", "VoiceAgentServerEventSessionSubagentAborted", "VoiceAgentServerEventSessionSubagentCompleted", "VoiceAgentServerEventSessionSubagentStarted", + "VoiceAgentServerEventSystemToolArgumentsDelta", + "VoiceAgentServerEventSystemToolArgumentsDone", "VoiceAgentServerEventWarning", "VoiceAgentServerEventWarningDetails", "VoiceAgentServerVadTurnDetection", @@ -1514,12 +2011,18 @@ "VoiceAgentSubagentConfig", "VoiceAgentSubagentResponsePolicy", "VoiceAgentSystemTool", + "VoiceAgentSystemToolItem", "VoiceAgentTemplateGreetingConfig", "VoiceAgentTool", "VoiceAgentToolboxTool", "VoiceAgentTranscriptionPhrase", "VoiceAgentTranscriptionWord", + "VoiceAgentTransferDestination", + "VoiceAgentTransferRouting", + "VoiceAgentTransferSystemTool", + "VoiceAgentTransferTarget", "VoiceAgentTurnDetectionConfig", + "VoiceAgentVoiceConfig", "VoiceAudioItem", "VoiceConversation", "VoiceConversationEngine", @@ -1569,6 +2072,7 @@ "AgentState", "AgentStateSource", "AgentVersionStatus", + "AnswerResourceType", "AttackStrategy", "AzureAISearchQueryType", "CallableToolAllowedCaller", @@ -1615,6 +2119,25 @@ "InputFidelity", "InsightType", "JobStatus", + "LiveAudioFormatType", + "LiveClientEventType", + "LiveContainerMemoryLimit", + "LiveDecisionInputItemParamType", + "LiveDecisionQuestionType", + "LiveDecisionStoredInputItemParamType", + "LiveDetailEnum", + "LiveFunctionCallItemStatus", + "LiveInitialItemType", + "LiveInitialMessageStatus", + "LiveReasoningEffort", + "LiveReasoningSummary", + "LiveResponsesServiceTier", + "LiveServerEventType", + "LiveSessionCreateParamsDelegationType", + "LiveSessionUpdateParamsDelegationType", + "LiveTextVerbosity", + "LiveToolChoiceEnum", + "LiveToolChoiceValueEnum", "MemoryItemKind", "MemoryOperationKind", "MemoryStoreKind", @@ -1623,6 +2146,7 @@ "Microsoft365PublishScope", "MicrosoftCopilotBuiltInTool", "MisalignmentErrorType", + "ModelIdsLive", "OpenApiAuthType", "OperationState", "OptimizationContextType", @@ -1638,6 +2162,7 @@ "RealtimeConversationItemType", "RealtimeMcpErrorType", "RealtimeReasoningEffort", + "RealtimeResponseInputMessageType", "RealtimeServerEventType", "ReasoningEffort", "ReasoningModeEnum", @@ -1664,7 +2189,7 @@ "TelemetryEndpointAuthType", "TelemetryEndpointKind", "TelemetryTransportProtocol", - "TelephonyBindingStatus", + "TelephonyAddressType", "TelephonyCallDurationBasis", "TelephonyCallEndReason", "TelephonyCallJobStatus", @@ -1678,10 +2203,11 @@ "TelephonyCallTimestampSource", "TelephonyCallTraceMode", "TelephonyCallTraceStatus", - "TelephonyOutboundDestinationType", + "TelephonyCampaignOperationKind", + "TelephonyCampaignScheduleType", + "TelephonyCampaignStatus", "TelephonyOutboundRetryPolicyType", "TelephonyProvider", - "TelephonyTransferDestinationKind", "TextResponseFormatConfigurationType", "ToolChoiceOptions", "ToolChoiceParamType", @@ -1697,23 +2223,49 @@ "VoiceAgentAudioTimestampType", "VoiceAgentAvatarOutputProtocol", "VoiceAgentAvatarType", + "VoiceAgentClientEventTypeExtension", + "VoiceAgentConversationItemTypeExtension", + "VoiceAgentDtmfTerminator", "VoiceAgentEchoCancellationReferenceSource", "VoiceAgentEndOfUtteranceDetectionModel", "VoiceAgentEndOfUtteranceThresholdLevel", + "VoiceAgentGreetingMode", + "VoiceAgentHandoffAbortReason", + "VoiceAgentHandoffPipelineFamily", + "VoiceAgentHandoffReasoningEffort", + "VoiceAgentHandoffTargetResponse", + "VoiceAgentInputCollectionChannel", + "VoiceAgentInputCollectionStatus", "VoiceAgentInputTranscriptionModel", "VoiceAgentInterimResponseTrigger", + "VoiceAgentInterimResponseType", + "VoiceAgentLiveConversationItemType", + "VoiceAgentLiveDelegationStatus", + "VoiceAgentLiveDelegationTarget", + "VoiceAgentLiveDelegationType", "VoiceAgentNoiseReductionType", + "VoiceAgentPostCallDestinationType", + "VoiceAgentPostCallIncludeOption", "VoiceAgentProfanityFilterMode", + "VoiceAgentRtcCallErrorType", + "VoiceAgentServerEventTypeExtension", "VoiceAgentSessionIncludeOption", "VoiceAgentSoundscapeSound", + "VoiceAgentSubProtocol", "VoiceAgentSubagentAbortReason", + "VoiceAgentSubagentType", + "VoiceAgentSystemToolItemStatus", "VoiceAgentSystemToolName", "VoiceAgentToolResponseScheduling", + "VoiceAgentToolType", + "VoiceAgentTransferDestinationType", + "VoiceAgentTransferStrategy", "VoiceAgentTransport", "VoiceAgentTurnDetectionType", "VoiceAudioCodec", "VoiceAudioContainerFormat", "VoiceAudioRole", + "VoiceConversationEngineType", "VoiceConversationStatus", "VoiceModelType", "VoiceOutputModality", 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 6590dd28ec1b..160e942193ca 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 @@ -399,6 +399,19 @@ class AgentVersionStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The agent version has been deleted.""" +class AnswerResourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of AnswerResourceType.""" + + PREDICATE = "predicate" + """PREDICATE.""" + CHOICE = "choice" + """CHOICE.""" + SCORE = "score" + """SCORE.""" + REFUSAL = "refusal" + """REFUSAL.""" + + class AttackStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Strategies for attacks.""" @@ -964,9 +977,9 @@ class IndexType(str, Enum, metaclass=CaseInsensitiveEnumMeta): class InputFidelity(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Control how much effort the model will exert to match the style and features, especially facial - features, of input images. This parameter is only supported for ``gpt-image-1`` and - ``gpt-image-1.5`` and later models, unsupported for ``gpt-image-1-mini``. Supports ``high`` and - ``low``. Defaults to ``low``. + features, of input images. Supports ``high`` and ``low`` on ``gpt-image-1.5``; + ``gpt-image-1-mini`` supports only ``low``. For ``gpt-image-2``, omit this parameter. Defaults + to ``low`` on supported models. """ HIGH = "high" @@ -1001,6 +1014,309 @@ class JobStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Job was cancelled by the caller.""" +class LiveAudioFormatType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveAudioFormatType.""" + + AUDIO_PCM = "audio/pcm" + """AUDIO_PCM.""" + AUDIO_PCMU = "audio/pcmu" + """AUDIO_PCMU.""" + AUDIO_PCMA = "audio/pcma" + """AUDIO_PCMA.""" + + +class LiveClientEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveClientEventType.""" + + SESSION_START = "session.start" + """SESSION_START.""" + SESSION_UPDATE = "session.update" + """SESSION_UPDATE.""" + SESSION_INPUT_AUDIO_APPEND = "session.input_audio.append" + """SESSION_INPUT_AUDIO_APPEND.""" + SESSION_INPUT_AUDIO_MUTE = "session.input_audio.mute" + """SESSION_INPUT_AUDIO_MUTE.""" + SESSION_INPUT_AUDIO_UNMUTE = "session.input_audio.unmute" + """SESSION_INPUT_AUDIO_UNMUTE.""" + SESSION_OUTPUT_AUDIO_FIXTURE_PLAY = "session.output_audio.fixture.play" + """SESSION_OUTPUT_AUDIO_FIXTURE_PLAY.""" + SESSION_INSTRUCTIONS_APPEND = "session.instructions.append" + """SESSION_INSTRUCTIONS_APPEND.""" + SESSION_THINKING_APPEND = "session.thinking.append" + """SESSION_THINKING_APPEND.""" + SESSION_COMMENTARY_APPEND = "session.commentary.append" + """SESSION_COMMENTARY_APPEND.""" + DECISION_CREATE = "decision.create" + """DECISION_CREATE.""" + DECISION_ITEM_CREATE = "decision.item.create" + """DECISION_ITEM_CREATE.""" + DECISION_ITEM_DELETE = "decision.item.delete" + """DECISION_ITEM_DELETE.""" + RESPONSE_ITEM_CREATE = "response.item.create" + """RESPONSE_ITEM_CREATE.""" + RESPONSE_CREATE = "response.create" + """RESPONSE_CREATE.""" + SESSION_CLOSE = "session.close" + """SESSION_CLOSE.""" + + +class LiveContainerMemoryLimit(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveContainerMemoryLimit.""" + + ENUM_1_G = "1g" + """1_G.""" + ENUM_4_G = "4g" + """4_G.""" + ENUM_16_G = "16g" + """16_G.""" + ENUM_64_G = "64g" + """64_G.""" + + +class LiveDecisionInputItemParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveDecisionInputItemParamType.""" + + MESSAGE = "message" + """MESSAGE.""" + FUNCTION_CALL = "function_call" + """FUNCTION_CALL.""" + FUNCTION_CALL_OUTPUT = "function_call_output" + """FUNCTION_CALL_OUTPUT.""" + CUSTOM_TOOL_CALL = "custom_tool_call" + """CUSTOM_TOOL_CALL.""" + CUSTOM_TOOL_CALL_OUTPUT = "custom_tool_call_output" + """CUSTOM_TOOL_CALL_OUTPUT.""" + + +class LiveDecisionQuestionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveDecisionQuestionType.""" + + CHOICE = "choice" + """CHOICE.""" + PREDICATE = "predicate" + """PREDICATE.""" + SCORE = "score" + """SCORE.""" + + +class LiveDecisionStoredInputItemParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveDecisionStoredInputItemParamType.""" + + MESSAGE = "message" + """MESSAGE.""" + FUNCTION_CALL = "function_call" + """FUNCTION_CALL.""" + FUNCTION_CALL_OUTPUT = "function_call_output" + """FUNCTION_CALL_OUTPUT.""" + CUSTOM_TOOL_CALL = "custom_tool_call" + """CUSTOM_TOOL_CALL.""" + CUSTOM_TOOL_CALL_OUTPUT = "custom_tool_call_output" + """CUSTOM_TOOL_CALL_OUTPUT.""" + + +class LiveDetailEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveDetailEnum.""" + + LOW = "low" + """LOW.""" + HIGH = "high" + """HIGH.""" + AUTO = "auto" + """AUTO.""" + ORIGINAL = "original" + """ORIGINAL.""" + + +class LiveFunctionCallItemStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveFunctionCallItemStatus.""" + + IN_PROGRESS = "in_progress" + """IN_PROGRESS.""" + COMPLETED = "completed" + """COMPLETED.""" + INCOMPLETE = "incomplete" + """INCOMPLETE.""" + + +class LiveInitialItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveInitialItemType.""" + + DEVELOPER = "developer" + """DEVELOPER.""" + USER = "user" + """USER.""" + ASSISTANT = "assistant" + """ASSISTANT.""" + + +class LiveInitialMessageStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveInitialMessageStatus.""" + + INCOMPLETE = "incomplete" + """INCOMPLETE.""" + COMPLETED = "completed" + """COMPLETED.""" + + +class LiveReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveReasoningEffort.""" + + NONE = "none" + """NONE.""" + MINIMAL = "minimal" + """MINIMAL.""" + LOW = "low" + """LOW.""" + MEDIUM = "medium" + """MEDIUM.""" + HIGH = "high" + """HIGH.""" + XHIGH = "xhigh" + """XHIGH.""" + + +class LiveReasoningSummary(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveReasoningSummary.""" + + CONCISE = "concise" + """CONCISE.""" + DETAILED = "detailed" + """DETAILED.""" + AUTO = "auto" + """AUTO.""" + + +class LiveResponsesServiceTier(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveResponsesServiceTier.""" + + AUTO = "auto" + """AUTO.""" + DEFAULT = "default" + """DEFAULT.""" + FAST_TIER_TEMP_PILOT = "fast_tier_temp_pilot" + """FAST_TIER_TEMP_PILOT.""" + FLEX = "flex" + """FLEX.""" + PRIORITY = "priority" + """PRIORITY.""" + ULTRAFAST = "ultrafast" + """ULTRAFAST.""" + + +class LiveServerEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveServerEventType.""" + + SESSION_STARTED = "session.started" + """SESSION_STARTED.""" + SESSION_UPDATED = "session.updated" + """SESSION_UPDATED.""" + SESSION_INPUT_AUDIO_MUTED = "session.input_audio.muted" + """SESSION_INPUT_AUDIO_MUTED.""" + SESSION_INPUT_AUDIO_UNMUTED = "session.input_audio.unmuted" + """SESSION_INPUT_AUDIO_UNMUTED.""" + SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING = "session.output_audio.fixture.playing" + """SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING.""" + SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED = "session.output_audio.fixture.played" + """SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED.""" + SESSION_INSTRUCTIONS_APPENDED = "session.instructions.appended" + """SESSION_INSTRUCTIONS_APPENDED.""" + SESSION_THINKING_APPENDED = "session.thinking.appended" + """SESSION_THINKING_APPENDED.""" + SESSION_COMMENTARY_APPENDED = "session.commentary.appended" + """SESSION_COMMENTARY_APPENDED.""" + SESSION_INPUT_AUDIO_APPEND = "session.input_audio.append" + """SESSION_INPUT_AUDIO_APPEND.""" + SESSION_OUTPUT_AUDIO_DELTA = "session.output_audio.delta" + """SESSION_OUTPUT_AUDIO_DELTA.""" + SESSION_INPUT_TRANSCRIPT_DELTA = "session.input_transcript.delta" + """SESSION_INPUT_TRANSCRIPT_DELTA.""" + SESSION_OUTPUT_TRANSCRIPT_DELTA = "session.output_transcript.delta" + """SESSION_OUTPUT_TRANSCRIPT_DELTA.""" + SESSION_DELEGATION_CREATED = "session.delegation.created" + """SESSION_DELEGATION_CREATED.""" + DECISION_EVENT = "decision.event" + """DECISION_EVENT.""" + DECISION_ITEM_CREATED = "decision.item.created" + """DECISION_ITEM_CREATED.""" + DECISION_ITEM_DELETED = "decision.item.deleted" + """DECISION_ITEM_DELETED.""" + RESPONSE_EVENT = "response.event" + """RESPONSE_EVENT.""" + SESSION_USAGE_UPDATED = "session.usage.updated" + """SESSION_USAGE_UPDATED.""" + SESSION_CLOSED = "session.closed" + """SESSION_CLOSED.""" + ERROR = "error" + """ERROR.""" + INFO = "info" + """INFO.""" + TRANSPORT_DTMF_RECEIVED = "transport.dtmf.received" + """TRANSPORT_DTMF_RECEIVED.""" + TRANSPORT_DTMF_SENT = "transport.dtmf.sent" + """TRANSPORT_DTMF_SENT.""" + TRANSPORT_RINGING = "transport.ringing" + """TRANSPORT_RINGING.""" + TRANSPORT_ANSWERED = "transport.answered" + """TRANSPORT_ANSWERED.""" + TRANSPORT_FAILED = "transport.failed" + """TRANSPORT_FAILED.""" + + +class LiveSessionCreateParamsDelegationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveSessionCreateParamsDelegationType.""" + + CLIENT = "client" + """CLIENT.""" + RESPONSES = "responses" + """RESPONSES.""" + DECISIONS = "decisions" + """DECISIONS.""" + + +class LiveSessionUpdateParamsDelegationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveSessionUpdateParamsDelegationType.""" + + CLIENT = "client" + """CLIENT.""" + RESPONSES = "responses" + """RESPONSES.""" + DECISIONS = "decisions" + """DECISIONS.""" + + +class LiveTextVerbosity(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveTextVerbosity.""" + + LOW = "low" + """LOW.""" + MEDIUM = "medium" + """MEDIUM.""" + HIGH = "high" + """HIGH.""" + + +class LiveToolChoiceEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveToolChoiceEnum.""" + + AUTO = "auto" + """AUTO.""" + NONE = "none" + """NONE.""" + REQUIRED = "required" + """REQUIRED.""" + + +class LiveToolChoiceValueEnum(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of LiveToolChoiceValueEnum.""" + + NONE = "none" + """NONE.""" + AUTO = "auto" + """AUTO.""" + REQUIRED = "required" + """REQUIRED.""" + + class MemoryItemKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Memory item kind.""" @@ -1097,6 +1413,15 @@ class MisalignmentErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """OTHER.""" +class ModelIdsLive(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The Live model. Required in the session configuration for every transport; do not pass it as a + URL query parameter. + """ + + GPT_LIVE1 = "gpt-live-1" + """GPT_LIVE1.""" + + class OpenApiAuthType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Authentication type for OpenApi endpoint. Allowed types are: @@ -1219,6 +1544,10 @@ class RealtimeAudioFormatsType(str, Enum, metaclass=CaseInsensitiveEnumMeta): class RealtimeClientEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of RealtimeClientEventType.""" + SESSION_AVATAR_CONNECT = "session.avatar.connect" + """SESSION_AVATAR_CONNECT.""" + RTC_CALL_SDP_CREATE = "rtc.call.sdp.create" + """RTC_CALL_SDP_CREATE.""" CONVERSATION_ITEM_CREATE = "conversation.item.create" """CONVERSATION_ITEM_CREATE.""" CONVERSATION_ITEM_DELETE = "conversation.item.delete" @@ -1241,10 +1570,6 @@ class RealtimeClientEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """RESPONSE_CREATE.""" SESSION_UPDATE = "session.update" """SESSION_UPDATE.""" - SESSION_AVATAR_CONNECT = "session.avatar.connect" - """SESSION_AVATAR_CONNECT.""" - RTC_CALL_SDP_CREATE = "rtc.call.sdp.create" - """RTC_CALL_SDP_CREATE.""" class RealtimeConversationItemMessageType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -1261,6 +1586,8 @@ class RealtimeConversationItemMessageType(str, Enum, metaclass=CaseInsensitiveEn class RealtimeConversationItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of RealtimeConversationItemType.""" + SYSTEM_TOOL = "system_tool" + """A service-managed system-tool intent, not a provider result.""" FUNCTION_CALL = "function_call" """FUNCTION_CALL.""" FUNCTION_CALL_OUTPUT = "function_call_output" @@ -1305,9 +1632,66 @@ class RealtimeReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): """XHIGH.""" +class RealtimeResponseInputMessageType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of RealtimeResponseInputMessageType.""" + + SYSTEM = "system" + """SYSTEM.""" + DEVELOPER = "developer" + """DEVELOPER.""" + USER = "user" + """USER.""" + ASSISTANT = "assistant" + """ASSISTANT.""" + + class RealtimeServerEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of RealtimeServerEventType.""" + WARNING = "warning" + """WARNING.""" + SESSION_SUBAGENT_STARTED = "session.subagent.started" + """SESSION_SUBAGENT_STARTED.""" + SESSION_SUBAGENT_COMPLETED = "session.subagent.completed" + """SESSION_SUBAGENT_COMPLETED.""" + SESSION_SUBAGENT_ABORTED = "session.subagent.aborted" + """SESSION_SUBAGENT_ABORTED.""" + SESSION_AVATAR_CONNECTING = "session.avatar.connecting" + """SESSION_AVATAR_CONNECTING.""" + SESSION_AVATAR_SWITCH_TO_SPEAKING = "session.avatar.switch_to_speaking" + """SESSION_AVATAR_SWITCH_TO_SPEAKING.""" + SESSION_AVATAR_SWITCH_TO_IDLE = "session.avatar.switch_to_idle" + """SESSION_AVATAR_SWITCH_TO_IDLE.""" + RTC_CALL_SDP_CREATED = "rtc.call.sdp.created" + """RTC_CALL_SDP_CREATED.""" + RTC_CALL_ERROR = "rtc.call.error" + """RTC_CALL_ERROR.""" + RESPONSE_AUDIO_TIMESTAMP_DELTA = "response.audio_timestamp.delta" + """RESPONSE_AUDIO_TIMESTAMP_DELTA.""" + RESPONSE_AUDIO_TIMESTAMP_DONE = "response.audio_timestamp.done" + """RESPONSE_AUDIO_TIMESTAMP_DONE.""" + RESPONSE_ANIMATION_BLENDSHAPES_DELTA = "response.animation_blendshapes.delta" + """RESPONSE_ANIMATION_BLENDSHAPES_DELTA.""" + RESPONSE_ANIMATION_BLENDSHAPES_DONE = "response.animation_blendshapes.done" + """RESPONSE_ANIMATION_BLENDSHAPES_DONE.""" + RESPONSE_ANIMATION_VISEME_DELTA = "response.animation_viseme.delta" + """RESPONSE_ANIMATION_VISEME_DELTA.""" + RESPONSE_ANIMATION_VISEME_DONE = "response.animation_viseme.done" + """RESPONSE_ANIMATION_VISEME_DONE.""" + RESPONSE_VIDEO_DELTA = "response.video.delta" + """RESPONSE_VIDEO_DELTA.""" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA = "response.system_tool_arguments.delta" + """An incremental fragment of model-generated system-tool arguments.""" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE = "response.system_tool_arguments.done" + """The complete model-generated system-tool arguments, not a provider outcome.""" + INPUT_COLLECTION_STATUS = "input_collection.status" + """An asynchronous collection or telephony-operation outcome.""" + SESSION_HANDOFF_STARTED = "session.handoff.started" + """SESSION_HANDOFF_STARTED.""" + SESSION_HANDOFF_COMPLETED = "session.handoff.completed" + """SESSION_HANDOFF_COMPLETED.""" + SESSION_HANDOFF_ABORTED = "session.handoff.aborted" + """SESSION_HANDOFF_ABORTED.""" CONVERSATION_CREATED = "conversation.created" """CONVERSATION_CREATED.""" CONVERSATION_ITEM_CREATED = "conversation.item.created" @@ -1400,38 +1784,6 @@ class RealtimeServerEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """RESPONSE_MCP_CALL_COMPLETED.""" RESPONSE_MCP_CALL_FAILED = "response.mcp_call.failed" """RESPONSE_MCP_CALL_FAILED.""" - WARNING = "warning" - """WARNING.""" - SESSION_SUBAGENT_STARTED = "session.subagent.started" - """SESSION_SUBAGENT_STARTED.""" - SESSION_SUBAGENT_COMPLETED = "session.subagent.completed" - """SESSION_SUBAGENT_COMPLETED.""" - SESSION_SUBAGENT_ABORTED = "session.subagent.aborted" - """SESSION_SUBAGENT_ABORTED.""" - SESSION_AVATAR_CONNECTING = "session.avatar.connecting" - """SESSION_AVATAR_CONNECTING.""" - SESSION_AVATAR_SWITCH_TO_SPEAKING = "session.avatar.switch_to_speaking" - """SESSION_AVATAR_SWITCH_TO_SPEAKING.""" - SESSION_AVATAR_SWITCH_TO_IDLE = "session.avatar.switch_to_idle" - """SESSION_AVATAR_SWITCH_TO_IDLE.""" - RTC_CALL_SDP_CREATED = "rtc.call.sdp.created" - """RTC_CALL_SDP_CREATED.""" - RTC_CALL_ERROR = "rtc.call.error" - """RTC_CALL_ERROR.""" - RESPONSE_AUDIO_TIMESTAMP_DELTA = "response.audio_timestamp.delta" - """RESPONSE_AUDIO_TIMESTAMP_DELTA.""" - RESPONSE_AUDIO_TIMESTAMP_DONE = "response.audio_timestamp.done" - """RESPONSE_AUDIO_TIMESTAMP_DONE.""" - RESPONSE_ANIMATION_BLENDSHAPES_DELTA = "response.animation_blendshapes.delta" - """RESPONSE_ANIMATION_BLENDSHAPES_DELTA.""" - RESPONSE_ANIMATION_BLENDSHAPES_DONE = "response.animation_blendshapes.done" - """RESPONSE_ANIMATION_BLENDSHAPES_DONE.""" - RESPONSE_ANIMATION_VISEME_DELTA = "response.animation_viseme.delta" - """RESPONSE_ANIMATION_VISEME_DELTA.""" - RESPONSE_ANIMATION_VISEME_DONE = "response.animation_viseme.done" - """RESPONSE_ANIMATION_VISEME_DONE.""" - RESPONSE_VIDEO_DELTA = "response.video.delta" - """RESPONSE_VIDEO_DELTA.""" class ReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -1439,7 +1791,7 @@ class ReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): ``minimal``, ``low``, ``medium``, ``high``, ``xhigh``, and ``max``. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response. Not all reasoning models support every value. See the `reasoning guide - `_ for model-specific support. + `_ for model-specific support. """ NONE = "none" @@ -1746,13 +2098,18 @@ class TelemetryTransportProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """gRPC transport protocol.""" -class TelephonyBindingStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The lifecycle status of a telephony binding.""" +class TelephonyAddressType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Extensible endpoint address kinds. Address type describes the endpoint independently of the + provider. + """ - ACTIVE = "active" - """The binding accepts new inbound calls.""" - SUSPENDED = "suspended" - """The binding remains configured but rejects new inbound calls.""" + PHONE_NUMBER = "phone_number" + """An E.164 phone number.""" + TEAMS = "teams" + """A Microsoft Teams identity. Source addresses require a nonempty resource-account object GUID; + transfer destinations also support 28:orgid:{guid}.""" + SIP = "sip" + """A SIP or SIPS destination for transfer.""" class TelephonyCallDurationBasis(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -2120,11 +2477,51 @@ class TelephonyCallTraceStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Trace creation failed.""" -class TelephonyOutboundDestinationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The type of destination for an outbound call.""" +class TelephonyCampaignOperationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Kind of asynchronous work associated with a Campaign.""" - PHONE_NUMBER = "phone_number" - """An E.164 phone number.""" + VALIDATION = "validation" + """Input validation and complete CallJob generation for a PUT.""" + CANCEL = "cancel" + """Stop future dispatch and drain admitted work.""" + DELETE = "delete" + """Cascade cleanup of Campaign task resources.""" + + +class TelephonyCampaignScheduleType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Mutually exclusive ways to determine each recipient's earliest dispatch time.""" + + IMMEDIATE = "immediate" + """Eligible automatically after successful preparation.""" + SCHEDULED = "scheduled" + """One common earliest dispatch time.""" + RECIPIENT = "recipient" + """A separate earliest dispatch time for each recipient.""" + + +class TelephonyCampaignStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Campaign execution state, separate from preparation/cancel/delete LROs. All recipients terminal + means completed, not necessarily successful. + """ + + VALIDATING = "validating" + """Validating recipients and generating CallJobs; no dialing until preparation succeeds.""" + RUNNING = "running" + """Preparation complete; jobs execute subject to schedule, capacity and retries.""" + CANCELLING = "cancelling" + """New dispatch stopped while admitted work drains; connected calls finish naturally. Cancellation + failure leaves dispatch stopped.""" + COMPLETED = "completed" + """All recipients terminal, including failed/expired jobs. Deletion waits for admitted work to + stop.""" + FAILED = "failed" + """Preparation failed without dialing and workers have stopped. Allows deletion or full + replacement.""" + CANCELLED = "cancelled" + """Cancellation complete. Can be deleted; unfinished work cannot restart.""" + DELETING = "deleting" + """Cleanup in progress; dialing and name reuse stay blocked until success, including after cleanup + failure.""" class TelephonyOutboundRetryPolicyType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -2143,19 +2540,8 @@ class TelephonyProvider(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Microsoft Teams Phone extensibility.""" TWILIO = "twilio" """Twilio Programmable Voice.""" - - -class TelephonyTransferDestinationKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The kind of telephony transfer destination. Known values are stable; additional values may be - added over time. - """ - - PSTN = "pstn" - """A public switched telephone network destination.""" - TEAMS = "teams" - """A Microsoft Teams user or resource-account destination.""" SIP = "sip" - """A Session Initiation Protocol destination.""" + """Session Initiation Protocol.""" class TextResponseFormatConfigurationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -2429,6 +2815,31 @@ class VoiceAgentAvatarType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """PHOTO_AVATAR.""" +class VoiceAgentClientEventTypeExtension(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of VoiceAgentClientEventTypeExtension.""" + + SESSION_AVATAR_CONNECT = "session.avatar.connect" + """SESSION_AVATAR_CONNECT.""" + RTC_CALL_SDP_CREATE = "rtc.call.sdp.create" + """RTC_CALL_SDP_CREATE.""" + + +class VoiceAgentConversationItemTypeExtension(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Additional item kinds used by the Voice Agent service.""" + + SYSTEM_TOOL = "system_tool" + """A service-managed system-tool intent, not a provider result.""" + + +class VoiceAgentDtmfTerminator(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The two non-numeric keypad keys permitted as confirmation terminators.""" + + NUMBER_SIGN = "#" + """The number-sign confirmation key.""" + ASTERISK = "*" + """The asterisk confirmation key.""" + + class VoiceAgentEchoCancellationReferenceSource( # pylint: disable=name-too-long str, Enum, metaclass=CaseInsensitiveEnumMeta ): @@ -2466,6 +2877,114 @@ class VoiceAgentEndOfUtteranceThresholdLevel(str, Enum, metaclass=CaseInsensitiv """The service-selected sensitivity threshold.""" +class VoiceAgentGreetingMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The greeting modes supported by a voice agent.""" + + TEMPLATE = "template" + """Speak a deterministic greeting rendered from a text template.""" + LLM_GENERATED = "llm_generated" + """Generate the greeting with the session model from an opening-turn prompt.""" + + +class VoiceAgentHandoffAbortReason(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Why a server-managed handoff ended before target commit.""" + + USER_INTERRUPTION = "user_interruption" + """USER_INTERRUPTION.""" + ERROR = "error" + """ERROR.""" + + +class VoiceAgentHandoffPipelineFamily(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The immutable pipeline family selected for a voice-agent handoff graph.""" + + CASCADED = "cascaded" + """CASCADED.""" + REALTIME = "realtime" + """REALTIME.""" + + +class VoiceAgentHandoffReasoningEffort(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Reasoning effort applied by a compatible handoff-node model.""" + + NONE = "none" + """NONE.""" + MINIMAL = "minimal" + """MINIMAL.""" + LOW = "low" + """LOW.""" + MEDIUM = "medium" + """MEDIUM.""" + HIGH = "high" + """HIGH.""" + XHIGH = "xhigh" + """XHIGH.""" + + +class VoiceAgentHandoffTargetResponse(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Whether Voice Live automatically starts a response after a handoff target becomes active.""" + + AUTO = "auto" + """AUTO.""" + NONE = "none" + """NONE.""" + + +class VoiceAgentInputCollectionChannel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The receiver used by an input collection. Voice collection is not supported.""" + + SMS = "sms" + """Receives one complete SMS from the selected sender.""" + DTMF = "dtmf" + """Receives individual keypad digits from the active call.""" + + +class VoiceAgentInputCollectionStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Collection lifecycle and value-free telephony-operation outcomes. Additional outcomes may be + introduced over time. + """ + + ACCEPTED = "accepted" + """The invocation was accepted; the receiver is not yet ready and no value has been collected.""" + LISTENING = "listening" + """The receiver is ready, allowing the service to prompt the caller for input.""" + COMPLETED = "completed" + """Collection completed with an ordinary value or a privately stored variable reference.""" + EXPIRED = "expired" + """A collection deadline or input timer expired without completing collection.""" + CANCELLED = "cancelled" + """The service cancelled collection and cleaned up its receiver.""" + FAILED = "failed" + """Collection failed without creating an output variable.""" + BUSY = "busy" + """The invocation was rejected because another operation is active.""" + INVALID_INPUT = "invalid_input" + """The received input did not satisfy the collection policy.""" + INVALID_ARGUMENTS = "invalid_arguments" + """The model-generated tool arguments were invalid.""" + STALE_COLLECTION = "stale_collection" + """The result does not match the current collection or receiver request.""" + UNSUPPORTED_CHANNEL = "unsupported_channel" + """No supported receiver. Also used when omitting an unsupported tool before model exposure; no + collection or variable is created.""" + DISPATCH_FAILED = "dispatch_failed" + """The service could not dispatch the operation to its executor; this does not confirm a provider + outcome.""" + PROVIDER_ACCEPTED = "provider_accepted" + """The provider accepted the operation; this does not confirm SMS delivery, IVR recognition or + authentication.""" + TRANSFER_NOT_ANSWERED = "transfer_not_answered" + """The transfer target did not answer and the original conversation remains available.""" + PROVIDER_FAILED_OR_UNSUPPORTED = "provider_failed_or_unsupported" + """The provider reported failure or does not support the requested operation.""" + PROVIDER_RESULT_UNCERTAIN = "provider_result_uncertain" + """The provider outcome could not be confirmed after possible dispatch; the service does not + automatically retry.""" + PROVIDER_NOT_EXECUTED = "provider_not_executed" + """Rejected before any provider side effect; nothing was sent or dialed. Includes unavailable + executors and unavailable-sender tool-resolution failures before model exposure.""" + + class VoiceAgentInputTranscriptionModel(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The input-audio transcription model identifier. This is a model name, not a Foundry deployment name. Mirrors the transcription models supported by the managed voice backend, covering the @@ -2510,6 +3029,63 @@ class VoiceAgentInterimResponseTrigger(str, Enum, metaclass=CaseInsensitiveEnumM """TOOL.""" +class VoiceAgentInterimResponseType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The interim-response implementations supported by a voice agent.""" + + STATIC_INTERIM_RESPONSE = "static_interim_response" + """Select a static interim response from configured text.""" + LLM_INTERIM_RESPONSE = "llm_interim_response" + """Generate an interim response with a language model.""" + + +class VoiceAgentLiveConversationItemType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The kind of a persisted Live conversation item.""" + + INPUT = "input" + """INPUT.""" + OUTPUT = "output" + """OUTPUT.""" + DELEGATION = "delegation" + """DELEGATION.""" + + +class VoiceAgentLiveDelegationStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Persisted delegation outcome, not speech or playback status.""" + + IN_PROGRESS = "in_progress" + """IN_PROGRESS.""" + COMPLETED = "completed" + """COMPLETED.""" + FAILED = "failed" + """FAILED.""" + INCOMPLETE = "incomplete" + """INCOMPLETE.""" + CANCELLED = "cancelled" + """CANCELLED.""" + + +class VoiceAgentLiveDelegationTarget(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Delegation owner. Foundry agent targets use native client delegation upstream.""" + + RESPONSES = "responses" + """RESPONSES.""" + CLIENT = "client" + """CLIENT.""" + FOUNDRY_MANAGED_AGENT = "foundry_managed_agent" + """FOUNDRY_MANAGED_AGENT.""" + + +class VoiceAgentLiveDelegationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Supported owners of work delegated by a Live voice agent.""" + + CLIENT = "client" + """The application handles delegated work.""" + RESPONSES = "responses" + """A Responses backend handles delegated work.""" + FOUNDRY_MANAGED_AGENT = "foundry_managed_agent" + """A prompt agent in the same project handles delegated work.""" + + class VoiceAgentNoiseReductionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The input audio noise reduction mode. @@ -2537,6 +3113,23 @@ class VoiceAgentNoiseReductionType(str, Enum, metaclass=CaseInsensitiveEnumMeta) unchanged; headset suppression remains active when personalization is unavailable.""" +class VoiceAgentPostCallDestinationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The type of a post-call destination.""" + + EVENT_GRID = "event_grid" + """An Event Grid connection.""" + ROUTINE = "routine" + """A routine.""" + + +class VoiceAgentPostCallIncludeOption(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Content that can be included in a post-call delivery.""" + + AUDIO = "audio" + """A URL to the merged call recording. Not supported in this preview: the service rejects + ``audio`` when the agent version is saved.""" + + class VoiceAgentProfanityFilterMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The supported input-transcript profanity filtering modes.""" @@ -2548,6 +3141,64 @@ class VoiceAgentProfanityFilterMode(str, Enum, metaclass=CaseInsensitiveEnumMeta """Removes recognized profanity from the transcript.""" +class VoiceAgentRtcCallErrorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The error categories reported for WebRTC signaling failures.""" + + INVALID_REQUEST_ERROR = "invalid_request_error" + """A client-side signaling fault, such as a malformed SDP offer.""" + SERVER_ERROR = "server_error" + """A service-side signaling failure.""" + + +class VoiceAgentServerEventTypeExtension(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of VoiceAgentServerEventTypeExtension.""" + + WARNING = "warning" + """WARNING.""" + SESSION_SUBAGENT_STARTED = "session.subagent.started" + """SESSION_SUBAGENT_STARTED.""" + SESSION_SUBAGENT_COMPLETED = "session.subagent.completed" + """SESSION_SUBAGENT_COMPLETED.""" + SESSION_SUBAGENT_ABORTED = "session.subagent.aborted" + """SESSION_SUBAGENT_ABORTED.""" + SESSION_AVATAR_CONNECTING = "session.avatar.connecting" + """SESSION_AVATAR_CONNECTING.""" + SESSION_AVATAR_SWITCH_TO_SPEAKING = "session.avatar.switch_to_speaking" + """SESSION_AVATAR_SWITCH_TO_SPEAKING.""" + SESSION_AVATAR_SWITCH_TO_IDLE = "session.avatar.switch_to_idle" + """SESSION_AVATAR_SWITCH_TO_IDLE.""" + RTC_CALL_SDP_CREATED = "rtc.call.sdp.created" + """RTC_CALL_SDP_CREATED.""" + RTC_CALL_ERROR = "rtc.call.error" + """RTC_CALL_ERROR.""" + RESPONSE_AUDIO_TIMESTAMP_DELTA = "response.audio_timestamp.delta" + """RESPONSE_AUDIO_TIMESTAMP_DELTA.""" + RESPONSE_AUDIO_TIMESTAMP_DONE = "response.audio_timestamp.done" + """RESPONSE_AUDIO_TIMESTAMP_DONE.""" + RESPONSE_ANIMATION_BLENDSHAPES_DELTA = "response.animation_blendshapes.delta" + """RESPONSE_ANIMATION_BLENDSHAPES_DELTA.""" + RESPONSE_ANIMATION_BLENDSHAPES_DONE = "response.animation_blendshapes.done" + """RESPONSE_ANIMATION_BLENDSHAPES_DONE.""" + RESPONSE_ANIMATION_VISEME_DELTA = "response.animation_viseme.delta" + """RESPONSE_ANIMATION_VISEME_DELTA.""" + RESPONSE_ANIMATION_VISEME_DONE = "response.animation_viseme.done" + """RESPONSE_ANIMATION_VISEME_DONE.""" + RESPONSE_VIDEO_DELTA = "response.video.delta" + """RESPONSE_VIDEO_DELTA.""" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA = "response.system_tool_arguments.delta" + """An incremental fragment of model-generated system-tool arguments.""" + RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE = "response.system_tool_arguments.done" + """The complete model-generated system-tool arguments, not a provider outcome.""" + INPUT_COLLECTION_STATUS = "input_collection.status" + """An asynchronous collection or telephony-operation outcome.""" + SESSION_HANDOFF_STARTED = "session.handoff.started" + """SESSION_HANDOFF_STARTED.""" + SESSION_HANDOFF_COMPLETED = "session.handoff.completed" + """SESSION_HANDOFF_COMPLETED.""" + SESSION_HANDOFF_ABORTED = "session.handoff.aborted" + """SESSION_HANDOFF_ABORTED.""" + + class VoiceAgentSessionIncludeOption(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Additional fields that a voice-agent session may include in service outputs.""" @@ -2595,6 +3246,35 @@ class VoiceAgentSubagentAbortReason(str, Enum, metaclass=CaseInsensitiveEnumMeta """The consultation failed.""" +class VoiceAgentSubagentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The subagent configuration mode. Additional modes may be added over time.""" + + DELEGATE = "delegate" + """Referenced Foundry agents invoked as delegated background specialists.""" + INLINE = "inline" + """Inline voice behaviors that may become active through Handoff.""" + + +class VoiceAgentSubProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Voice protocol; realtime includes cascaded models.""" + + REALTIME = "realtime" + """REALTIME.""" + LIVE = "live" + """LIVE.""" + + +class VoiceAgentSystemToolItemStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The generation status of a system-tool item. It does not indicate provider success.""" + + IN_PROGRESS = "in_progress" + """The item is still being generated.""" + COMPLETED = "completed" + """The item finished generation.""" + INCOMPLETE = "incomplete" + """The item did not finish generation.""" + + class VoiceAgentSystemToolName(str, Enum, metaclass=CaseInsensitiveEnumMeta): """A service-managed voice-session control action. Known values are stable; additional values may be added over time. @@ -2602,6 +3282,20 @@ class VoiceAgentSystemToolName(str, Enum, metaclass=CaseInsensitiveEnumMeta): END_CONVERSATION = "end_conversation" """Ends the active conversation.""" + LANGUAGE_DETECTION = "language_detection" + """Switches supported conversation language settings.""" + DIGIT_RECOGNITION = "digit_recognition" + """Retrieves the unchanged transcript of the last user audio turn.""" + TRANSFER = "transfer" + """Requests a transfer to an explicitly configured logical target.""" + COLLECT_SMS = "collect_sms" + """Collects one complete SMS from an explicitly selected sender.""" + COLLECT_DTMF = "collect_dtmf" + """Collects keypad digits on the current call.""" + SEND_DTMF = "send_dtmf" + """Sends literal or templated keypad digits.""" + SEND_SMS = "send_sms" + """Sends a text message from the Agent's SMS-capable number.""" class VoiceAgentToolResponseScheduling(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -2617,6 +3311,44 @@ class VoiceAgentToolResponseScheduling(str, Enum, metaclass=CaseInsensitiveEnumM """Create a follow-up response only when no response is active.""" +class VoiceAgentToolType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The tool kinds supported by a voice agent.""" + + FUNCTION = "function" + """A native function tool executed by the client.""" + MCP = "mcp" + """A tool exposed by an MCP server.""" + SYSTEM = "system" + """A service-managed control that acts on the active voice session.""" + TOOLBOX = "toolbox" + """A reference to a Foundry toolbox.""" + + +class VoiceAgentTransferDestinationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The supported address formats for a system-tool transfer destination.""" + + PHONE_NUMBER = "phone_number" + """An E.164 telephone number.""" + TEAMS = "teams" + """A Microsoft Teams user or resource-account identifier.""" + SIP = "sip" + """A SIP or SIPS URI.""" + + +class VoiceAgentTransferStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Per-invocation transfer routing. Unsupported strategies are rejected before provider execution; + schema membership does not imply support by every provider. + """ + + SEQUENTIAL = "sequential" + """Try destinations in configured order while the total budget remains.""" + RANDOM = "random" + """Randomize destination order for this invocation, then try each within the total budget.""" + PARALLEL = "parallel" + """Ring destinations concurrently and select the first answer when the executor supports this + strategy.""" + + class VoiceAgentTransport(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The transport used for a voice-agent connection.""" @@ -2668,6 +3400,13 @@ class VoiceAudioRole(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Audio produced by the agent.""" +class VoiceConversationEngineType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The conversation engine types supported by a voice agent.""" + + HOSTED_AGENT = "hosted_agent" + """Use a hosted Foundry agent to handle the conversation.""" + + class VoiceConversationStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The lifecycle status of a persisted voice conversation: 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 fca3df7ac84d..83f8cee29332 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py @@ -22,6 +22,7 @@ AgentOptimizationDataSourceType, AgentOptimizationEvaluationSetType, AgentOptimizationTargetConfigurationType, + AnswerResourceType, ContainerNetworkPolicyParamType, ContainerSkillType, CreateTranscriptionResponseJsonUsageType, @@ -40,6 +41,15 @@ FunctionShellToolParamEnvironmentType, IndexType, InsightType, + LiveAudioFormatType, + LiveClientEventType, + LiveDecisionInputItemParamType, + LiveDecisionQuestionType, + LiveDecisionStoredInputItemParamType, + LiveInitialItemType, + LiveServerEventType, + LiveSessionCreateParamsDelegationType, + LiveSessionUpdateParamsDelegationType, MemoryItemKind, MemoryStoreKind, MemoryStoreObjectType, @@ -51,6 +61,7 @@ RealtimeConversationItemMessageType, RealtimeConversationItemType, RealtimeMcpErrorType, + RealtimeResponseInputMessageType, RealtimeServerEventType, RecurrenceType, RoutineActionType, @@ -61,9 +72,10 @@ TargetAttribute, TelemetryEndpointAuthType, TelemetryEndpointKind, + TelephonyAddressType, + TelephonyCampaignScheduleType, TelephonyOutboundRetryPolicyType, TelephonyProvider, - TelephonyTransferDestinationKind, TextResponseFormatConfigurationType, ToolChoiceParamType, ToolType, @@ -71,8 +83,24 @@ TriggerType, VersionIndicatorType, VersionSelectorType, + VoiceAgentAudioTimestampType, + VoiceAgentClientEventTypeExtension, + VoiceAgentConversationItemTypeExtension, + VoiceAgentGreetingMode, + VoiceAgentInterimResponseType, + VoiceAgentLiveConversationItemType, + VoiceAgentLiveDelegationTarget, + VoiceAgentLiveDelegationType, + VoiceAgentPostCallDestinationType, + VoiceAgentServerEventTypeExtension, + VoiceAgentSubProtocol, + VoiceAgentSubagentType, VoiceAgentSystemToolName, + VoiceAgentToolType, VoiceAgentTurnDetectionType, + VoiceAudioRole, + VoiceConversationEngineType, + VoiceModelType, ) if TYPE_CHECKING: @@ -960,8 +988,8 @@ class AgentDefinition(_Model): # pylint: disable=docstring-keyword-should-match """AgentDefinition. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ExternalAgentDefinition, HostedAgentDefinition, PromptAgentDefinition, VoiceAgentDefinition, - WorkflowAgentDefinition + ExternalAgentDefinition, HostedAgentDefinition, PromptAgentDefinition, + VoiceAgentBaseDefinition, WorkflowAgentDefinition :ivar kind: Required. Known values are: "prompt", "hosted", "workflow", "external", and "voice". @@ -4664,6 +4692,218 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class AnswerResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A completed question always includes its name, including null when unnamed. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + AnswerResourceChoice, AnswerResourcePredicate, AnswerResourceRefusal, AnswerResourceScore + + :ivar type: Required. Known values are: "predicate", "choice", "score", and "refusal". + :vartype type: str or ~azure.ai.projects.models.AnswerResourceType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"predicate\", \"choice\", \"score\", and \"refusal\".""" + + @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 AnswerResourceChoice( + AnswerResource, discriminator="choice" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """AnswerResourceChoice. + + :ivar type: The type of the object. Always ``choice``. Required. CHOICE. + :vartype type: str or ~azure.ai.projects.models.CHOICE + :ivar name: Required. + :vartype name: str + :ivar choice: Required. Is either a str type or a bool type. + :vartype choice: str or bool + :ivar probabilities: Required. + :vartype probabilities: list[~azure.ai.projects.models.ChoiceProbabilityResource] + :ivar confidence: Required. + :vartype confidence: float + """ + + type: Literal[AnswerResourceType.CHOICE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the object. Always ``choice``. Required. CHOICE.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + choice: "_unions.ChoiceValueResource" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a str type or a bool type.""" + probabilities: list["_models.ChoiceProbabilityResource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + confidence: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + name: str, + choice: "_unions.ChoiceValueResource", + probabilities: list["_models.ChoiceProbabilityResource"], + confidence: 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) + self.type = AnswerResourceType.CHOICE # type: ignore + + +class AnswerResourcePredicate( + AnswerResource, discriminator="predicate" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """AnswerResourcePredicate. + + :ivar type: The type of the object. Always ``predicate``. Required. PREDICATE. + :vartype type: str or ~azure.ai.projects.models.PREDICATE + :ivar name: Required. + :vartype name: str + :ivar probability: Required. + :vartype probability: float + """ + + type: Literal[AnswerResourceType.PREDICATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the object. Always ``predicate``. Required. PREDICATE.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + probability: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + name: str, + probability: 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) + self.type = AnswerResourceType.PREDICATE # type: ignore + + +class AnswerResourceRefusal( + AnswerResource, discriminator="refusal" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The model declined to answer this question. Other questions in the same request can still + receive answers. + + :ivar type: The type of the object. Always ``refusal``. Required. REFUSAL. + :vartype type: str or ~azure.ai.projects.models.REFUSAL + :ivar name: Required. + :vartype name: str + """ + + type: Literal[AnswerResourceType.REFUSAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the object. Always ``refusal``. Required. REFUSAL.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + 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) + self.type = AnswerResourceType.REFUSAL # type: ignore + + +class AnswerResourceScore( + AnswerResource, discriminator="score" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """AnswerResourceScore. + + :ivar type: The type of the object. Always ``score``. Required. SCORE. + :vartype type: str or ~azure.ai.projects.models.SCORE + :ivar name: Required. + :vartype name: str + :ivar score: Required. + :vartype score: float + :ivar probabilities: Required. + :vartype probabilities: list[~azure.ai.projects.models.ScoreProbabilityResource] + :ivar confidence: Required. + :vartype confidence: float + """ + + type: Literal[AnswerResourceType.SCORE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the object. Always ``score``. Required. SCORE.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + score: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + probabilities: list["_models.ScoreProbabilityResource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + confidence: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + name: str, + score: float, + probabilities: list["_models.ScoreProbabilityResource"], + confidence: 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) + self.type = AnswerResourceType.SCORE # type: ignore + + class ApiError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """ApiError. @@ -4910,6 +5150,94 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class TelephonyCampaignSchedule(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Creation authorizes dialing; every scheduling mode waits for successful preparation. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + ImmediateSchedule, PerRecipientSchedule, AtTimeSchedule + + :ivar type: How each recipient's earliest dispatch time is determined. Required. Known values + are: "immediate", "scheduled", and "recipient". + :vartype type: str or ~azure.ai.projects.models.TelephonyCampaignScheduleType + :ivar expires_at: Exclusive deadline for new attempts, including retries; active calls may + finish. Must be later than every scheduled_at. + :vartype expires_at: ~datetime.datetime + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """How each recipient's earliest dispatch time is determined. Required. Known values are: + \"immediate\", \"scheduled\", and \"recipient\".""" + expires_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """Exclusive deadline for new attempts, including retries; active calls may finish. Must be later + than every scheduled_at.""" + + @overload + def __init__( + self, + *, + type: str, + expires_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 AtTimeSchedule( + TelephonyCampaignSchedule, discriminator="scheduled" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Uses one earliest dispatch time for all recipients. Past times are allowed; preparation must + still succeed. + + :ivar expires_at: Exclusive deadline for new attempts, including retries; active calls may + finish. Must be later than every scheduled_at. + :vartype expires_at: ~datetime.datetime + :ivar type: Identifies scheduling with one common earliest dispatch time. Required. One common + earliest dispatch time. + :vartype type: str or ~azure.ai.projects.models.SCHEDULED + :ivar scheduled_at: Common earliest dispatch time; successful preparation is required. + Required. + :vartype scheduled_at: ~datetime.datetime + """ + + type: Literal[TelephonyCampaignScheduleType.SCHEDULED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Identifies scheduling with one common earliest dispatch time. Required. One common earliest + dispatch time.""" + scheduled_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """Common earliest dispatch time; successful preparation is required. Required.""" + + @overload + def __init__( + self, + *, + scheduled_at: datetime.datetime, + expires_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) + self.type = TelephonyCampaignScheduleType.SCHEDULED # type: ignore + + class AutoCodeInterpreterToolParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Automatic Code Interpreter Tool Parameters. @@ -6499,6 +6827,39 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.kind = MemoryItemKind.CHAT_SUMMARY # type: ignore +class ChoiceProbabilityResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """ChoiceProbabilityResource. + + :ivar value: Required. Is either a str type or a bool type. + :vartype value: str or bool + :ivar probability: Required. + :vartype probability: float + """ + + value: "_unions.ChoiceValueResource" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a str type or a bool type.""" + probability: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + value: "_unions.ChoiceValueResource", + probability: 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 ClusterInsightResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Insights from the cluster analysis. @@ -6806,6 +7167,11 @@ class CodeInterpreterTool( :vartype type: str or ~azure.ai.projects.models.CODE_INTERPRETER :ivar allowed_callers: :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] + :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 + AutoCodeInterpreterToolParam type. + :vartype container: str or ~azure.ai.projects.models.AutoCodeInterpreterToolParam :ivar name: Deprecated. This property is deprecated and will be removed in a future version. :vartype name: str :ivar description: Deprecated. This property is deprecated and will be removed in a future @@ -6814,11 +7180,6 @@ class CodeInterpreterTool( :ivar tool_configs: Deprecated. This property is deprecated and will be removed in a future version. :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 - AutoCodeInterpreterToolParam type. - :vartype container: str or ~azure.ai.projects.models.AutoCodeInterpreterToolParam """ type: Literal[ToolType.CODE_INTERPRETER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore @@ -6826,6 +7187,13 @@ class CodeInterpreterTool( allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) + container: Optional[Union[str, "_models.AutoCodeInterpreterToolParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """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 AutoCodeInterpreterToolParam + type.""" name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Deprecated. This property is deprecated and will be removed in a future version.""" description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -6834,23 +7202,16 @@ class CodeInterpreterTool( visibility=["read", "create", "update", "delete", "query"] ) """Deprecated. This property is deprecated and will be removed in a future version.""" - container: Optional[Union[str, "_models.AutoCodeInterpreterToolParam"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """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 AutoCodeInterpreterToolParam - type.""" @overload def __init__( self, *, allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = None, + container: Optional[Union[str, "_models.AutoCodeInterpreterToolParam"]] = None, name: Optional[str] = None, description: Optional[str] = None, tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, - container: Optional[Union[str, "_models.AutoCodeInterpreterToolParam"]] = None, ) -> None: ... @overload @@ -7001,13 +7362,14 @@ class CompoundFilter(_Model): # pylint: disable=docstring-keyword-should-match- :vartype type: str or str :ivar filters: Array of filters to combine. Items can be ``ComparisonFilter`` or ``CompoundFilter``. Required. - :vartype filters: list[~azure.ai.projects.models.ComparisonFilter or any] + :vartype filters: list[~azure.ai.projects.models.ComparisonFilter or + ~azure.ai.projects.models.CompoundFilter] """ type: Literal["and", "or"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Type of operation: ``and`` or ``or``. Required. Is either a Literal[\"and\"] type or a Literal[\"or\"] type.""" - filters: list[Union["_models.ComparisonFilter", Any]] = rest_field( + filters: list[Union["_models.ComparisonFilter", "_models.CompoundFilter"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) """Array of filters to combine. Items can be ``ComparisonFilter`` or ``CompoundFilter``. Required.""" @@ -7017,7 +7379,7 @@ def __init__( self, *, type: Literal["and", "or"], - filters: list[Union["_models.ComparisonFilter", Any]], + filters: list[Union["_models.ComparisonFilter", "_models.CompoundFilter"]], ) -> None: ... @overload @@ -7685,180 +8047,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CreateTelephonyBindingRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The request to create a telephony binding. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - CreateTeamsPhoneExtensibilityTelephonyBindingRequest, CreateTwilioTelephonyBindingRequest - - :ivar provider: The telephony provider. Required. Known values are: "teams_phone_extensibility" - and "twilio". - :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: An optional display label for the binding. - :vartype label: str - """ - - __mapping__: dict[str, _Model] = {} - provider: str = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) - """The telephony provider. Required. Known values are: \"teams_phone_extensibility\" and - \"twilio\".""" - connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Foundry connection name for the telephony provider. Required.""" - label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional display label for the binding.""" - - @overload - def __init__( - self, - *, - provider: str, - connection_name: str, - label: 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 CreateTeamsPhoneExtensibilityTelephonyBindingRequest( - CreateTelephonyBindingRequest, discriminator="teams_phone_extensibility" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """The request to create a Microsoft Teams Phone extensibility binding. - - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: An optional display label for the binding. - :vartype label: str - :ivar provider: The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams - Phone extensibility. - :vartype provider: str or ~azure.ai.projects.models.TEAMS_PHONE_EXTENSIBILITY - :ivar phone_number: The optional display phone number for the Teams resource account. - :vartype phone_number: str - :ivar resource_account_object_id: The Microsoft Teams resource-account object identifier as a - GUID. Required. - :vartype resource_account_object_id: str - """ - - provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams Phone - extensibility.""" - phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The optional display phone number for the Teams resource account.""" - resource_account_object_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Microsoft Teams resource-account object identifier as a GUID. Required.""" - - @overload - def __init__( - self, - *, - connection_name: str, - resource_account_object_id: str, - label: Optional[str] = None, - phone_number: 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.provider = TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY # type: ignore - - -class CreateTelephonyCallJobRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A request to create one durable direct outbound call job. - - :ivar destination: The phone destination to call. Required. - :vartype destination: ~azure.ai.projects.models.TelephonyOutboundDestination - :ivar connection_name: The Foundry connection name in the current project used to originate the - call. Its category selects Twilio or Azure Communication Services / Teams Phone extensibility. - No inbound telephony binding is required. Required. - :vartype connection_name: str - :ivar source: The caller identity used to originate the call. For a Twilio connection, provide - an authorized E.164 phone number. For an Azure Communication Services / Teams Phone - extensibility connection, provide the Teams Resource Account object ID. The identity type is - inferred from the connection category; originating does not change inbound routing. Required. - :vartype source: str - :ivar purpose: An optional customer-declared purpose for placing the call. - :vartype purpose: str - :ivar structured_inputs: Structured input values available to the agent and greeting for this - call. Agent-declared inputs are validated against their schemas; omitted optional inputs may - use their Agent-defined default values, while omitted required inputs are rejected. Additional - inputs remain available as dynamic template variables. - :vartype structured_inputs: dict[str, any] - :ivar schedule: The optional execution window. - :vartype schedule: ~azure.ai.projects.models.TelephonyCallJobSchedule - :ivar retry_policy: The provider-attempt retry policy. Omit it for one attempt with no retry - delay. - :vartype retry_policy: ~azure.ai.projects.models.TelephonyOutboundRetryPolicy - """ - - destination: "_models.TelephonyOutboundDestination" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The phone destination to call. Required.""" - connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Foundry connection name in the current project used to originate the call. Its category - selects Twilio or Azure Communication Services / Teams Phone extensibility. No inbound - telephony binding is required. Required.""" - source: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The caller identity used to originate the call. For a Twilio connection, provide an authorized - E.164 phone number. For an Azure Communication Services / Teams Phone extensibility connection, - provide the Teams Resource Account object ID. The identity type is inferred from the connection - category; originating does not change inbound routing. Required.""" - purpose: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional customer-declared purpose for placing the call.""" - structured_inputs: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Structured input values available to the agent and greeting for this call. Agent-declared - inputs are validated against their schemas; omitted optional inputs may use their Agent-defined - default values, while omitted required inputs are rejected. Additional inputs remain available - as dynamic template variables.""" - schedule: Optional["_models.TelephonyCallJobSchedule"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The optional execution window.""" - retry_policy: Optional["_models.TelephonyOutboundRetryPolicy"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The provider-attempt retry policy. Omit it for one attempt with no retry delay.""" - - @overload - def __init__( - self, - *, - destination: "_models.TelephonyOutboundDestination", - connection_name: str, - source: str, - purpose: Optional[str] = None, - structured_inputs: Optional[dict[str, Any]] = None, - schedule: Optional["_models.TelephonyCallJobSchedule"] = None, - retry_policy: Optional["_models.TelephonyOutboundRetryPolicy"] = 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 CreateTranscriptionResponseJsonUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Token usage statistics for the request. @@ -7891,47 +8079,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CreateTwilioTelephonyBindingRequest( - CreateTelephonyBindingRequest, discriminator="twilio" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """The request to create a Twilio binding. - - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: An optional display label for the binding. - :vartype label: str - :ivar provider: The Twilio provider. Required. Twilio Programmable Voice. - :vartype provider: str or ~azure.ai.projects.models.TWILIO - :ivar phone_number: The Twilio E.164 phone number. Required. - :vartype phone_number: str - """ - - provider: Literal[TelephonyProvider.TWILIO] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Twilio provider. Required. Twilio Programmable Voice.""" - phone_number: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Twilio E.164 phone number. Required.""" - - @overload - def __init__( - self, - *, - connection_name: str, - phone_number: str, - label: 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.provider = TelephonyProvider.TWILIO # type: ignore - - class Trigger(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Base model for Trigger of the schedule. @@ -8804,18 +8951,18 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class DatasetReference(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Reference to a versioned Foundry Dataset. + """Reference to a Dataset whose concrete version has already been resolved. :ivar name: Dataset name. Required. :vartype name: str - :ivar version: Dataset version. Required. + :ivar version: Concrete Dataset version. Required. :vartype version: str """ 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.""" + """Concrete Dataset version. Required.""" @overload def __init__( @@ -8910,6 +9057,48 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class DecisionResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """DecisionResponse. + + :ivar model: The model used. Required. + :vartype model: str + :ivar answers: Answers in question order. Any question can return a refusal instead of an + answer; other questions can still receive answers. A refusal has ``type: "refusal"`` and the + question's ``name``, or ``null`` if it was unnamed. Required. + :vartype answers: list[~azure.ai.projects.models.AnswerResource] + :ivar usage: Token usage for the request. Required. + :vartype usage: ~azure.ai.projects.models.ResponseUsageResource + """ + + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model used. Required.""" + answers: list["_models.AnswerResource"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Answers in question order. Any question can return a refusal instead of an answer; other + questions can still receive answers. A refusal has ``type: \"refusal\"`` and the question's + ``name``, or ``null`` if it was unnamed. Required.""" + usage: "_models.ResponseUsageResource" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Token usage for the request. Required.""" + + @overload + def __init__( + self, + *, + model: str, + answers: list["_models.AnswerResource"], + usage: "_models.ResponseUsageResource", + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class DeleteAgentResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """A deleted agent Object. @@ -11485,6 +11674,92 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolboxToolType.FILE_SEARCH # type: ignore +class TelephonyOutboundRetryPolicy(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The retry policy for one durable outbound call intent. ``max_attempts`` includes the first + attempt. Strategy-specific settings are defined by the derived policy. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + FixedIntervalRetryPolicy + + :ivar type: The retry strategy. Only fixed-interval retries are currently supported. Required. + "fixed_interval" + :vartype type: str or ~azure.ai.projects.models.TelephonyOutboundRetryPolicyType + :ivar max_attempts: The maximum number of provider attempts, including the first attempt. + Defaults to 1. + :vartype max_attempts: int + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The retry strategy. Only fixed-interval retries are currently supported. Required. + \"fixed_interval\"""" + max_attempts: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The maximum number of provider attempts, including the first attempt. Defaults to 1.""" + + @overload + def __init__( + self, + *, + type: str, + max_attempts: 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 FixedIntervalRetryPolicy( + TelephonyOutboundRetryPolicy, discriminator="fixed_interval" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Shared direct-call/Campaign retry policy. Omission means one attempt; CallJobs return + max_attempts=1 and interval=0 seconds. + + :ivar max_attempts: The maximum number of provider attempts, including the first attempt. + Defaults to 1. + :vartype max_attempts: int + :ivar type: The fixed-interval retry strategy. Required. Retry after a fixed interval between + attempts. + :vartype type: str or ~azure.ai.projects.models.FIXED_INTERVAL + :ivar interval: The nonnegative delay between attempts, from 0 to 2147483647 seconds. Zero + permits an immediate retry, subject to scheduling and capacity. Required. + :vartype interval: ~datetime.timedelta + """ + + type: Literal[TelephonyOutboundRetryPolicyType.FIXED_INTERVAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The fixed-interval retry strategy. Required. Retry after a fixed interval between attempts.""" + interval: datetime.timedelta = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + ) + """The nonnegative delay between attempts, from 0 to 2147483647 seconds. Zero permits an immediate + retry, subject to scheduling and capacity. Required.""" + + @overload + def __init__( + self, + *, + interval: datetime.timedelta, + max_attempts: Optional[int] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = TelephonyOutboundRetryPolicyType.FIXED_INTERVAL # type: ignore + + class VersionSelectionRule(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """VersionSelectionRule. @@ -11700,9 +11975,9 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class FunctionParameters(_Model): """The parameters the functions accepts, described as a JSON Schema object. See the `guide - `_ for examples, and the `JSON Schema reference - `_ for documentation about the format. - Omitting ``parameters`` defines a function with an empty parameter list. + `_ for examples, and the `JSON + Schema reference `_ for documentation about + the format. Omitting ``parameters`` defines a function with an empty parameter list. """ @@ -12570,23 +12845,26 @@ class ImageGenTool( :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"], Literal["gpt-image-2"], - Literal["gpt-image-2-2026-04-21"], str - :vartype model: str or str or 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 images. For ``gpt-image-2`` and - ``gpt-image-2-2026-04-21``, arbitrary resolutions are supported as ``WIDTHxHEIGHT`` strings, - for example ``1536x864``. Width and height must both be divisible by 16 and the requested - aspect ratio must be between 1:3 and 3:1. Resolutions above ``2560x1440`` are experimental, and - the maximum supported resolution is ``3840x2160``. The requested size must also satisfy the - model's current pixel and edge limits. The standard sizes ``1024x1024``, ``1536x1024``, and - ``1024x1536`` are supported by the GPT image models; ``auto`` is supported for models that - allow automatic sizing. For ``dall-e-2``, use one of ``256x256``, ``512x512``, or - ``1024x1024``. For ``dall-e-3``, use one of ``1024x1024``, ``1792x1024``, or ``1024x1792``. Is - one of the following types: Literal["1024x1024"], Literal["1024x1536"], Literal["1536x1024"], - Literal["auto"], str + Literal["gpt-image-2-2026-04-21"], Literal["gpt-image-2.5-sunburst"], + Literal["gpt-image-2.5-sunburst-2026-09-08"], Literal["gpt-image-2.5-flare"], + Literal["gpt-image-2.5-flare-2026-09-08"], str + :vartype model: str or str or str or str or str or str or str or str or str or str + :ivar quality: The quality of the generated image. The GPT image models support ``low``, + ``medium``, and ``high``. ``gpt-image-2.5-sunburst`` and ``gpt-image-2.5-flare``, including + their ``2026-09-08`` snapshots, also support ``xhigh`` and ``max``. Default: ``auto``. Is one + of the following types: Literal["low"], Literal["medium"], Literal["high"], Literal["xhigh"], + Literal["max"], Literal["auto"] + :vartype quality: str or str or str or str or str or str + :ivar size: The size of the generated images. For ``gpt-image-2``, ``gpt-image-2-2026-04-21``, + ``gpt-image-2.5-sunburst``, ``gpt-image-2.5-sunburst-2026-09-08``, ``gpt-image-2.5-flare``, and + ``gpt-image-2.5-flare-2026-09-08``, arbitrary resolutions are supported as ``WIDTHxHEIGHT`` + strings, for example ``1536x864``. Width and height must both be divisible by 16 and the + requested aspect ratio must be between 1:3 and 3:1. Resolutions above ``2560x1440`` are + experimental, and the maximum supported resolution is ``3840x2160``. The requested size must + also satisfy the model's current pixel and edge limits. The standard sizes ``1024x1024``, + ``1536x1024``, and ``1024x1536`` are supported by the GPT image models; ``auto`` is supported + for models that allow automatic sizing. Is one of the following types: Literal["1024x1024"], + Literal["1024x1536"], Literal["1536x1024"], Literal["auto"], str :vartype size: str or 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"], @@ -12598,10 +12876,12 @@ class ImageGenTool( Literal["auto"] type or a Literal["low"] type. :vartype moderation: str or str :ivar background: Set the background of the generated image. One of ``transparent``, - ``opaque``, or ``auto``. Transparent backgrounds are available for supported GPT Image models. - For ``gpt-image-2`` and ``gpt-image-2-2026-04-21``, this support is in preview. When using - ``transparent``, set the output format to ``png`` or ``webp``. Default: ``auto``. Is one of the - following types: Literal["transparent"], Literal["opaque"], Literal["auto"] + ``opaque``, or ``auto``. ``gpt-image-2.5-sunburst`` and ``gpt-image-2.5-flare``, including + their ``2026-09-08`` snapshots, support ``opaque`` and ``transparent`` backgrounds. Transparent + backgrounds are available for supported GPT Image models. For ``gpt-image-2`` and + ``gpt-image-2-2026-04-21``, this support is in preview. When using ``transparent``, set the + output format to ``png`` or ``webp``. 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 @@ -12633,30 +12913,38 @@ class ImageGenTool( Literal["gpt-image-1.5"], Literal["gpt-image-2"], Literal["gpt-image-2-2026-04-21"], + Literal["gpt-image-2.5-sunburst"], + Literal["gpt-image-2.5-sunburst-2026-09-08"], + Literal["gpt-image-2.5-flare"], + Literal["gpt-image-2.5-flare-2026-09-08"], 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\"], Literal[\"gpt-image-2\"], Literal[\"gpt-image-2-2026-04-21\"], str""" - quality: Optional[Literal["low", "medium", "high", "auto"]] = rest_field( + Literal[\"gpt-image-1.5\"], Literal[\"gpt-image-2\"], Literal[\"gpt-image-2-2026-04-21\"], + Literal[\"gpt-image-2.5-sunburst\"], Literal[\"gpt-image-2.5-sunburst-2026-09-08\"], + Literal[\"gpt-image-2.5-flare\"], Literal[\"gpt-image-2.5-flare-2026-09-08\"], str""" + quality: Optional[Literal["low", "medium", "high", "xhigh", "max", "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\"]""" + """The quality of the generated image. The GPT image models support ``low``, ``medium``, and + ``high``. ``gpt-image-2.5-sunburst`` and ``gpt-image-2.5-flare``, including their + ``2026-09-08`` snapshots, also support ``xhigh`` and ``max``. Default: ``auto``. Is one of the + following types: Literal[\"low\"], Literal[\"medium\"], Literal[\"high\"], Literal[\"xhigh\"], + Literal[\"max\"], Literal[\"auto\"]""" size: Optional[Union[Literal["1024x1024"], Literal["1024x1536"], Literal["1536x1024"], Literal["auto"], str]] = ( rest_field(visibility=["read", "create", "update", "delete", "query"]) ) - """The size of the generated images. For ``gpt-image-2`` and ``gpt-image-2-2026-04-21``, arbitrary - resolutions are supported as ``WIDTHxHEIGHT`` strings, for example ``1536x864``. Width and - height must both be divisible by 16 and the requested aspect ratio must be between 1:3 and 3:1. - Resolutions above ``2560x1440`` are experimental, and the maximum supported resolution is - ``3840x2160``. The requested size must also satisfy the model's current pixel and edge limits. - The standard sizes ``1024x1024``, ``1536x1024``, and ``1024x1536`` are supported by the GPT - image models; ``auto`` is supported for models that allow automatic sizing. For ``dall-e-2``, - use one of ``256x256``, ``512x512``, or ``1024x1024``. For ``dall-e-3``, use one of - ``1024x1024``, ``1792x1024``, or ``1024x1792``. Is one of the following types: - Literal[\"1024x1024\"], Literal[\"1024x1536\"], Literal[\"1536x1024\"], Literal[\"auto\"], str""" + """The size of the generated images. For ``gpt-image-2``, ``gpt-image-2-2026-04-21``, + ``gpt-image-2.5-sunburst``, ``gpt-image-2.5-sunburst-2026-09-08``, ``gpt-image-2.5-flare``, and + ``gpt-image-2.5-flare-2026-09-08``, arbitrary resolutions are supported as ``WIDTHxHEIGHT`` + strings, for example ``1536x864``. Width and height must both be divisible by 16 and the + requested aspect ratio must be between 1:3 and 3:1. Resolutions above ``2560x1440`` are + experimental, and the maximum supported resolution is ``3840x2160``. The requested size must + also satisfy the model's current pixel and edge limits. The standard sizes ``1024x1024``, + ``1536x1024``, and ``1024x1536`` are supported by the GPT image models; ``auto`` is supported + for models that allow automatic sizing. Is one of the following types: Literal[\"1024x1024\"], + Literal[\"1024x1536\"], Literal[\"1536x1024\"], Literal[\"auto\"], str""" output_format: Optional[Literal["png", "webp", "jpeg"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -12673,10 +12961,12 @@ class ImageGenTool( visibility=["read", "create", "update", "delete", "query"] ) """Set the background of the generated image. One of ``transparent``, ``opaque``, or ``auto``. - Transparent backgrounds are available for supported GPT Image models. For ``gpt-image-2`` and - ``gpt-image-2-2026-04-21``, this support is in preview. When using ``transparent``, set the - output format to ``png`` or ``webp``. Default: ``auto``. Is one of the following types: - Literal[\"transparent\"], Literal[\"opaque\"], Literal[\"auto\"]""" + ``gpt-image-2.5-sunburst`` and ``gpt-image-2.5-flare``, including their ``2026-09-08`` + snapshots, support ``opaque`` and ``transparent`` backgrounds. Transparent backgrounds are + available for supported GPT Image models. For ``gpt-image-2`` and ``gpt-image-2-2026-04-21``, + this support is in preview. When using ``transparent``, set the output format to ``png`` or + ``webp``. 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"] ) @@ -12713,10 +13003,14 @@ def __init__( Literal["gpt-image-1.5"], Literal["gpt-image-2"], Literal["gpt-image-2-2026-04-21"], + Literal["gpt-image-2.5-sunburst"], + Literal["gpt-image-2.5-sunburst-2026-09-08"], + Literal["gpt-image-2.5-flare"], + Literal["gpt-image-2.5-flare-2026-09-08"], str, ] ] = None, - quality: Optional[Literal["low", "medium", "high", "auto"]] = None, + quality: Optional[Literal["low", "medium", "high", "xhigh", "max", "auto"]] = None, size: Optional[ Union[Literal["1024x1024"], Literal["1024x1536"], Literal["1536x1024"], Literal["auto"], str] ] = None, @@ -12776,6 +13070,42 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class ImmediateSchedule( + TelephonyCampaignSchedule, discriminator="immediate" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Dispatch automatically as soon as preparation succeeds and capacity permits. + + :ivar expires_at: Exclusive deadline for new attempts, including retries; active calls may + finish. Must be later than every scheduled_at. + :vartype expires_at: ~datetime.datetime + :ivar type: Identifies immediate scheduling after successful preparation. Required. Eligible + automatically after successful preparation. + :vartype type: str or ~azure.ai.projects.models.IMMEDIATE + """ + + type: Literal[TelephonyCampaignScheduleType.IMMEDIATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Identifies immediate scheduling after successful preparation. Required. Eligible automatically + after successful preparation.""" + + @overload + def __init__( + self, + *, + expires_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) + self.type = TelephonyCampaignScheduleType.IMMEDIATE # type: ignore + + class InlineSkillParam( ContainerSkill, discriminator="inline" ): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -12862,6 +13192,205 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.media_type: Literal["application/zip"] = "application/zip" +class InlineVoiceSubagent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """One inline voice subagent owned and versioned with its parent Voice Agent, not a separate Agent + resource. + + :ivar id: The subagent identifier. New Handoff authoring requires ``$entrypoint`` as the first + subagent; other values use the normal handoff ID grammar. Required. + :vartype id: str + :ivar source: The definition source. This phase supports only ``inline``; referenced Agent + resources are deferred. Required. Default value is "inline". + :vartype source: str + :ivar interface: The interaction interface. This phase supports only ``voice``; text delegation + is deferred. Required. Default value is "voice". + :vartype interface: str + :ivar display_description: A non-empty display-only description of the specialist behavior. + This value is not provided to the model. Required. + :vartype display_description: str + :ivar model: The target model for a cascaded graph. Realtime graphs reject this property and + retain the connection model. + :vartype model: str + :ivar instructions: Subagent-specific instructions. With default inheritance, non-empty + instructions follow the original top-level instructions. Omission, null, or an empty string + adds nothing after that base. With inheritance disabled, only this value applies. + :vartype instructions: str + :ivar inherit_base_instructions: Whether the subagent inherits the original top-level + instructions before applying its own non-empty instructions. Defaults to true; set to false to + opt out. + :vartype inherit_base_instructions: bool + :ivar tools: Customer tools available to this subagent. Omission or null selects an empty + customer tool set. + :vartype tools: list[~azure.ai.projects.models.VoiceAgentTool] + :ivar tool_choice: Tool-selection behavior for this subagent. If omitted, the service defaults + to auto. Null also selects auto. Is one of the following types: Literal["none"], + Literal["auto"], Literal["required"], ToolChoiceFunction, ToolChoiceMCP + :vartype tool_choice: str or str or str or ~azure.ai.projects.models.ToolChoiceFunction or + ~azure.ai.projects.models.ToolChoiceMCP + :ivar audio_output: The output voice configuration activated for this subagent, using the same + flat voice fields as the top-level audio output. Omission inherits the entrypoint + configuration; a supplied object replaces the voice-specific settings. + :vartype audio_output: ~azure.ai.projects.models.VoiceAgentVoiceConfig + :ivar temperature: The sampling temperature for a compatible subagent model, from 0 through 2. + :vartype temperature: float + :ivar max_response_output_tokens: The maximum output-token count for one response while this + subagent is active. Is either a int type or a Literal["inf"] type. + :vartype max_response_output_tokens: int or str + :ivar reasoning_effort: Reasoning effort for a compatible subagent model. Known values are: + "none", "minimal", "low", "medium", "high", and "xhigh". + :vartype reasoning_effort: str or ~azure.ai.projects.models.VoiceAgentHandoffReasoningEffort + :ivar voice_adaptation: Voice-optimized instruction adaptation for this subagent. Null disables + adaptation. + :vartype voice_adaptation: ~azure.ai.projects.models.VoiceAgentHandoffVoiceAdaptation + :ivar interim_response: Interim-response settings for this subagent. Null disables interim + responses. + :vartype interim_response: ~azure.ai.projects.models.VoiceAgentInterimResponseConfig + :ivar parallel_tool_calls: Whether this subagent may call customer tools in parallel. If + omitted, the service defaults to false. Subagents with outgoing handoff conditions must use + ``false``. + :vartype parallel_tool_calls: bool + :ivar handoff_conditions: Outgoing handoffs from this subagent. The containing subagent + supplies each condition's source. The service permits at most 128 conditions across the entire + Agent. + :vartype handoff_conditions: list[~azure.ai.projects.models.VoiceAgentHandoffCondition] + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The subagent identifier. New Handoff authoring requires ``$entrypoint`` as the first subagent; + other values use the normal handoff ID grammar. Required.""" + source: Literal["inline"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The definition source. This phase supports only ``inline``; referenced Agent resources are + deferred. Required. Default value is \"inline\".""" + interface: Literal["voice"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The interaction interface. This phase supports only ``voice``; text delegation is deferred. + Required. Default value is \"voice\".""" + display_description: str = rest_field( + name="description", visibility=["read", "create", "update", "delete", "query"] + ) + """A non-empty display-only description of the specialist behavior. This value is not provided to + the model. Required.""" + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target model for a cascaded graph. Realtime graphs reject this property and retain the + connection model.""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Subagent-specific instructions. With default inheritance, non-empty instructions follow the + original top-level instructions. Omission, null, or an empty string adds nothing after that + base. With inheritance disabled, only this value applies.""" + inherit_base_instructions: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the subagent inherits the original top-level instructions before applying its own + non-empty instructions. Defaults to true; set to false to opt out.""" + tools: Optional[list["_models.VoiceAgentTool"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Customer tools available to this subagent. Omission or null selects an empty customer tool set.""" + tool_choice: Optional["_unions.VoiceAgentToolChoice"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Tool-selection behavior for this subagent. If omitted, the service defaults to auto. Null also + selects auto. Is one of the following types: Literal[\"none\"], Literal[\"auto\"], + Literal[\"required\"], ToolChoiceFunction, ToolChoiceMCP""" + audio_output: Optional["_models.VoiceAgentVoiceConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The output voice configuration activated for this subagent, using the same flat voice fields as + the top-level audio output. Omission inherits the entrypoint configuration; a supplied object + replaces the voice-specific settings.""" + temperature: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The sampling temperature for a compatible subagent model, from 0 through 2.""" + max_response_output_tokens: Optional["_unions.VoiceAgentHandoffMaxOutputTokens"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The maximum output-token count for one response while this subagent is active. Is either a int + type or a Literal[\"inf\"] type.""" + reasoning_effort: Optional[Union[str, "_models.VoiceAgentHandoffReasoningEffort"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Reasoning effort for a compatible subagent model. Known values are: \"none\", \"minimal\", + \"low\", \"medium\", \"high\", and \"xhigh\".""" + voice_adaptation: Optional["_models.VoiceAgentHandoffVoiceAdaptation"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Voice-optimized instruction adaptation for this subagent. Null disables adaptation.""" + interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Interim-response settings for this subagent. Null disables interim responses.""" + parallel_tool_calls: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether this subagent may call customer tools in parallel. If omitted, the service defaults to + false. Subagents with outgoing handoff conditions must use ``false``.""" + handoff_conditions: Optional[list["_models.VoiceAgentHandoffCondition"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Outgoing handoffs from this subagent. The containing subagent supplies each condition's source. + The service permits at most 128 conditions across the entire Agent.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + display_description: str, + model: Optional[str] = None, + instructions: Optional[str] = None, + inherit_base_instructions: Optional[bool] = None, + tools: Optional[list["_models.VoiceAgentTool"]] = None, + tool_choice: Optional["_unions.VoiceAgentToolChoice"] = None, + audio_output: Optional["_models.VoiceAgentVoiceConfig"] = None, + temperature: Optional[float] = None, + max_response_output_tokens: Optional["_unions.VoiceAgentHandoffMaxOutputTokens"] = None, + reasoning_effort: Optional[Union[str, "_models.VoiceAgentHandoffReasoningEffort"]] = None, + voice_adaptation: Optional["_models.VoiceAgentHandoffVoiceAdaptation"] = None, + interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = None, + parallel_tool_calls: Optional[bool] = None, + handoff_conditions: Optional[list["_models.VoiceAgentHandoffCondition"]] = 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.source: Literal["inline"] = "inline" + self.interface: Literal["voice"] = "voice" + + +class InputTokensDetailsResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """InputTokensDetailsResource. + + :ivar cached_tokens: Required. + :vartype cached_tokens: int + :ivar cache_write_tokens: Required. + :vartype cache_write_tokens: int + """ + + cached_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + cache_write_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + cached_tokens: int, + cache_write_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 Insight(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """The response body for cluster insights. @@ -13407,41 +13936,110 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = RoutineActionType.INVOKE_AGENT_RESPONSES_API # type: ignore -class LocalShellToolParam( - Tool, discriminator="local_shell" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Local shell tool. +class LiveAllowedServerEventParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Live server event selector for the WebRTC frontend data channel. - :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: Deprecated. This property is deprecated and will be removed in a future version. - :vartype name: str - :ivar description: Deprecated. This property is deprecated and will be removed in a future - version. - :vartype description: str - :ivar tool_configs: Deprecated. This property is deprecated and will be removed in a future - version. - :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + :ivar type: The outer Live server event type. Use 'response.event' for Responses events. + Required. + :vartype type: str + :ivar response_event: The nested Responses event type. Required when type is 'response.event'; + forbidden for other event types. + :vartype response_event: str """ - 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"]) - """Deprecated. This property is deprecated and will be removed in a future version.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Deprecated. This property is deprecated and will be removed in a future version.""" - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The outer Live server event type. Use 'response.event' for Responses events. Required.""" + response_event: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The nested Responses event type. Required when type is 'response.event'; forbidden for other + event types.""" + + @overload + def __init__( + self, + *, + type: str, + response_event: 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 LiveAllowedToolsChoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveAllowedToolsChoiceParam. + + :ivar type: The tool choice type. Always ``allowed_tools``. Required. Default value is + "allowed_tools". + :vartype type: str + :ivar tools: The tools that the delegated Responses model may call. Required. + :vartype tools: list[~azure.ai.projects.models.LiveFunctionToolChoiceParam or + ~azure.ai.projects.models.LiveMCPToolChoiceParam or + ~azure.ai.projects.models.LiveSpecificFileSearchParam or + ~azure.ai.projects.models.LiveSpecificWebSearchParam or + ~azure.ai.projects.models.LiveSpecificWebSearchPreviewParam or + ~azure.ai.projects.models.LiveSpecificImageGenParam or + ~azure.ai.projects.models.LiveSpecificComputerParam or + ~azure.ai.projects.models.LiveSpecificCodeInterpreterParam or + ~azure.ai.projects.models.LiveSpecificProgrammaticToolCallingParam or + ~azure.ai.projects.models.LiveSpecificFunctionShellParam or + ~azure.ai.projects.models.LiveSpecificCustomToolParam or + ~azure.ai.projects.models.LiveSpecificApplyPatchParam] + :ivar mode: Known values are: "none", "auto", and "required". + :vartype mode: str or ~azure.ai.projects.models.LiveToolChoiceValueEnum + """ + + type: Literal["allowed_tools"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool choice type. Always ``allowed_tools``. Required. Default value is \"allowed_tools\".""" + tools: list[ + Union[ + "_models.LiveFunctionToolChoiceParam", + "_models.LiveMCPToolChoiceParam", + "_models.LiveSpecificFileSearchParam", + "_models.LiveSpecificWebSearchParam", + "_models.LiveSpecificWebSearchPreviewParam", + "_models.LiveSpecificImageGenParam", + "_models.LiveSpecificComputerParam", + "_models.LiveSpecificCodeInterpreterParam", + "_models.LiveSpecificProgrammaticToolCallingParam", + "_models.LiveSpecificFunctionShellParam", + "_models.LiveSpecificCustomToolParam", + "_models.LiveSpecificApplyPatchParam", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tools that the delegated Responses model may call. Required.""" + mode: Optional[Union[str, "_models.LiveToolChoiceValueEnum"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Deprecated. This property is deprecated and will be removed in a future version.""" + """Known values are: \"none\", \"auto\", and \"required\".""" @overload def __init__( self, *, - name: Optional[str] = None, - description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + tools: list[ + Union[ + "_models.LiveFunctionToolChoiceParam", + "_models.LiveMCPToolChoiceParam", + "_models.LiveSpecificFileSearchParam", + "_models.LiveSpecificWebSearchParam", + "_models.LiveSpecificWebSearchPreviewParam", + "_models.LiveSpecificImageGenParam", + "_models.LiveSpecificComputerParam", + "_models.LiveSpecificCodeInterpreterParam", + "_models.LiveSpecificProgrammaticToolCallingParam", + "_models.LiveSpecificFunctionShellParam", + "_models.LiveSpecificCustomToolParam", + "_models.LiveSpecificApplyPatchParam", + ] + ], + mode: Optional[Union[str, "_models.LiveToolChoiceValueEnum"]] = None, ) -> None: ... @overload @@ -13453,34 +14051,45 @@ 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 + self.type: Literal["allowed_tools"] = "allowed_tools" -class LocalSkillParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """LocalSkillParam. +class LiveApplyPatchToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveApplyPatchToolInputParam. - :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 type: Required. Default value is "apply_patch". + :vartype type: 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.""" + type: Literal["apply_patch"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"apply_patch\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["apply_patch"] = "apply_patch" + + +class LiveAudioFormat(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Audio encoding and sample rate for audio sent and received over a Live WebSocket connection. + WebRTC and SIP negotiate their media format separately. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveSessionAudioFormatPCMParam, LiveSessionAudioFormatPCMAParam, + LiveSessionAudioFormatPCMUParam + + :ivar type: Required. Known values are: "audio/pcm", "audio/pcmu", and "audio/pcma". + :vartype type: str or ~azure.ai.projects.models.LiveAudioFormatType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"audio/pcm\", \"audio/pcmu\", and \"audio/pcma\".""" @overload def __init__( self, *, - name: str, - description: str, - path: str, + type: str, ) -> None: ... @overload @@ -13494,31 +14103,25 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class LogProbProperties(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A log probability object. +class LiveClientConfigParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Startup-only capabilities for an untrusted frontend attached to a unified WebRTC session. + Trusted sideband connections are unaffected. - :ivar token: The token that was used to generate the log probability. Required. - :vartype token: str - :ivar logprob: The log probability of the token. Required. - :vartype logprob: float - :ivar bytes: The bytes that were used to generate the log probability. Required. - :vartype bytes: list[int] + :ivar data_channel: Client and server event permissions for the WebRTC frontend data channel. + Required. + :vartype data_channel: ~azure.ai.projects.models.LiveDataChannelConfigParam """ - token: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The token that was used to generate the log probability. Required.""" - logprob: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The log probability of the token. Required.""" - bytes: list[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The bytes that were used to generate the log probability. Required.""" + data_channel: "_models.LiveDataChannelConfigParam" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Client and server event permissions for the WebRTC frontend data channel. Required.""" @overload def __init__( self, *, - token: str, - logprob: float, - bytes: list[int], + data_channel: "_models.LiveDataChannelConfigParam", ) -> None: ... @overload @@ -13532,41 +14135,45 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class LoraConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Adapter-specific metadata for LoRA models. Drives serving engine configuration at deployment - time. +class LiveClientEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Client events for Live. Initialize a primary WebSocket with session.start and wait for + session.started. WebRTC creation already starts the session. Audio append is primary + WebSocket-only. See the `Live prompting guide + `_ before writing frontend + instructions and delegation policies. - :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 + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveClientEventLiveDecisionCreateParam, LiveClientEventLiveDecisionItemCreateParam, + LiveClientEventLiveDecisionItemDeleteParam, LiveClientEventLiveResponseCreateParam, + LiveClientEventLiveResponseItemCreateParam, LiveClientEventLiveSessionCloseParam, + LiveClientEventLiveCommentaryAppendParam, LiveClientEventLiveInputAudioAppendEvent, + LiveClientEventLiveInputAudioMuteParam, LiveClientEventLiveInputAudioUnmuteParam, + LiveClientEventLiveInstructionsAppendParam, LiveClientEventLiveOutputAudioFixturePlayParam, + LiveSessionStartEvent, LiveClientEventLiveThinkingAppendParam, + LiveClientEventLiveSessionUpdateParam + + :ivar type: Required. Known values are: "session.start", "session.update", + "session.input_audio.append", "session.input_audio.mute", "session.input_audio.unmute", + "session.output_audio.fixture.play", "session.instructions.append", "session.thinking.append", + "session.commentary.append", "decision.create", "decision.item.create", "decision.item.delete", + "response.item.create", "response.create", and "session.close". + :vartype type: str or ~azure.ai.projects.models.LiveClientEventType """ - 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.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"session.start\", \"session.update\", + \"session.input_audio.append\", \"session.input_audio.mute\", \"session.input_audio.unmute\", + \"session.output_audio.fixture.play\", \"session.instructions.append\", + \"session.thinking.append\", \"session.commentary.append\", \"decision.create\", + \"decision.item.create\", \"decision.item.delete\", \"response.item.create\", + \"response.create\", and \"session.close\".""" @overload def __init__( self, *, - rank: Optional[int] = None, - alpha: Optional[int] = None, - target_modules: Optional[list[str]] = None, - dropout: Optional[float] = None, + type: str, ) -> None: ... @overload @@ -13580,27 +14187,41 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ManagedAgentIdentityBlueprintReference( - AgentBlueprintReference, discriminator="ManagedAgentIdentityBlueprint" +class LiveClientEventLiveCommentaryAppendParam( + LiveClientEvent, discriminator="session.commentary.append" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """ManagedAgentIdentityBlueprintReference. + """Provide context the Live model can communicate to the user, optionally for an existing client + delegation. Rejected while an audio fixture is active. - :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 event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.commentary.append``. Required. + SESSION_COMMENTARY_APPEND. + :vartype type: str or ~azure.ai.projects.models.SESSION_COMMENTARY_APPEND + :ivar delegation_id: Required. + :vartype delegation_id: str + :ivar content: Speakable context for the Live model, limited to 500 tokens. Use this for a + result the model should communicate; use session.thinking.append for silent context. Required. + :vartype content: 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.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_COMMENTARY_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.commentary.append``. Required. + SESSION_COMMENTARY_APPEND.""" + delegation_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + content: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Speakable context for the Live model, limited to 500 tokens. Use this for a result the model + should communicate; use session.thinking.append for silent context. Required.""" @overload def __init__( self, *, - blueprint_id: str, + delegation_id: str, + content: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -13612,42 +14233,31 @@ 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 + self.type = LiveClientEventType.SESSION_COMMENTARY_APPEND # type: ignore -class ManagedAzureAISearchIndex( - Index, discriminator="ManagedAzureSearch" +class LiveClientEventLiveDecisionCreateParam( + LiveClientEvent, discriminator="decision.create" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Managed Azure AI Search Index Definition. + """Evaluate the configured questions using the current conversation and Decision inputs. Reusing + an event_id is rejected for the lifetime of the session. - :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 + :ivar event_id: Required. + :vartype event_id: str + :ivar type: Required. DECISION_CREATE. + :vartype type: str or ~azure.ai.projects.models.DECISION_CREATE """ - 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.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + type: Literal[LiveClientEventType.DECISION_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISION_CREATE.""" @overload def __init__( self, *, - vector_store_id: str, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + event_id: str, ) -> None: ... @overload @@ -13659,41 +14269,35 @@ 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 + self.type = LiveClientEventType.DECISION_CREATE # type: ignore -class MCPListToolsTool(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """MCP list tools tool. +class LiveClientEventLiveDecisionItemCreateParam( + LiveClientEvent, discriminator="decision.item.create" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Append an input item for future decisions without starting an evaluation or changing Live voice + context. - :ivar name: The name of the tool. Required. - :vartype name: str - :ivar description: - :vartype description: str - :ivar input_schema: The JSON schema describing the tool's input. Required. - :vartype input_schema: ~azure.ai.projects.models.MCPListToolsToolInputSchema - :ivar annotations: - :vartype annotations: ~azure.ai.projects.models.MCPListToolsToolAnnotations + :ivar event_id: + :vartype event_id: str + :ivar type: Required. DECISION_ITEM_CREATE. + :vartype type: str or ~azure.ai.projects.models.DECISION_ITEM_CREATE + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.LiveDecisionInputItemParam """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the tool. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - input_schema: "_models.MCPListToolsToolInputSchema" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The JSON schema describing the tool's input. Required.""" - annotations: Optional["_models.MCPListToolsToolAnnotations"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.DECISION_ITEM_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISION_ITEM_CREATE.""" + item: "_models.LiveDecisionInputItemParam" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - name: str, - input_schema: "_models.MCPListToolsToolInputSchema", - description: Optional[str] = None, - annotations: Optional["_models.MCPListToolsToolAnnotations"] = None, + item: "_models.LiveDecisionInputItemParam", + event_id: Optional[str] = None, ) -> None: ... @overload @@ -13705,172 +14309,120 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveClientEventType.DECISION_ITEM_CREATE # type: ignore -class MCPListToolsToolAnnotations(_Model): - """MCPListToolsToolAnnotations.""" +class LiveClientEventLiveDecisionItemDeleteParam( + LiveClientEvent, discriminator="decision.item.delete" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Delete an input item from future decisions without starting an evaluation or changing Live + voice context. + :ivar event_id: + :vartype event_id: str + :ivar type: Required. DECISION_ITEM_DELETE. + :vartype type: str or ~azure.ai.projects.models.DECISION_ITEM_DELETE + :ivar item_id: Required. + :vartype item_id: str + """ -class MCPListToolsToolInputSchema(_Model): - """MCPListToolsToolInputSchema.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.DECISION_ITEM_DELETE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISION_ITEM_DELETE.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + @overload + def __init__( + self, + *, + item_id: str, + event_id: Optional[str] = None, + ) -> None: ... -class McpProtocolConfiguration(_Model): - """Configuration specific to the MCP protocol.""" + @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 = LiveClientEventType.DECISION_ITEM_DELETE # type: ignore -class MCPTool(Tool, discriminator="mcp"): # pylint: disable=docstring-keyword-should-match-keyword-only - """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``, ``connector_id``, or - ``tunnel_id`` must be provided. - :vartype server_url: str - :ivar connector_id: Identifier for service connectors, like those available in ChatGPT. One of - ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. Learn more about service - connectors `here `_. Currently supported - ``connector_id`` values are: +class LiveClientEventLiveInputAudioAppendEvent( + LiveClientEvent, discriminator="session.input_audio.append" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Send audio to a Live session over its primary WebSocket. WebRTC and SIP sessions send audio + over their media transport. - * 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"] + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.input_audio.append``. Required. + SESSION_INPUT_AUDIO_APPEND. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_AUDIO_APPEND + :ivar audio: Base64-encoded raw audio in the startup-selected format, without a WAV or other + container header. Primary WebSocket only; media transports use their audio track. Audio appends + have no acknowledgment. Reflected sideband server events reuse this event type and audio key, + with no timestamps or event_id; their audio is always mono PCM16LE at 24 kHz. Required. + :vartype audio: str + """ - :vartype connector_id: str or str or str or str or str or str or str or str - :ivar tunnel_id: The Secure MCP Tunnel ID to use instead of a direct server URL. One of - ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. - :vartype tunnel_id: 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 allowed_callers: - :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] - :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 defer_loading: Whether this MCP tool is deferred and discovered via tool search. - :vartype defer_loading: bool - :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: Deprecated. This property is deprecated and will be removed in a future - version. - :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_INPUT_AUDIO_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.input_audio.append``. Required. + SESSION_INPUT_AUDIO_APPEND.""" + audio: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64-encoded raw audio in the startup-selected format, without a WAV or other container + header. Primary WebSocket only; media transports use their audio track. Audio appends have no + acknowledgment. Reflected sideband server events reuse this event type and audio key, with no + timestamps or event_id; their audio is always mono PCM16LE at 24 kHz. Required.""" + + @overload + def __init__( + self, + *, + audio: str, + event_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 = LiveClientEventType.SESSION_INPUT_AUDIO_APPEND # type: ignore + + +class LiveClientEventLiveInputAudioMuteParam( + LiveClientEvent, discriminator="session.input_audio.mute" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Mute audio input to the Live model without closing the session. The server acknowledges with + ``session.input_audio.muted``. + + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.input_audio.mute``. Required. + SESSION_INPUT_AUDIO_MUTE. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_AUDIO_MUTE """ - 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``, ``connector_id``, or ``tunnel_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``, - ``connector_id``, or ``tunnel_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\"]""" - tunnel_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Secure MCP Tunnel ID to use instead of a direct server URL. One of ``server_url``, - ``connector_id``, or ``tunnel_id`` must be provided.""" - 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.""" - allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - 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\"]""" - defer_loading: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether this MCP tool is deferred and discovered via tool search.""" - 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"] - ) - """Deprecated. This property is deprecated and will be removed in a future version.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_INPUT_AUDIO_MUTE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.input_audio.mute``. Required. + SESSION_INPUT_AUDIO_MUTE.""" @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, - tunnel_id: Optional[str] = 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, - allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = None, - require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = None, - defer_loading: Optional[bool] = None, - project_connection_id: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -13882,164 +14434,85 @@ 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 + self.type = LiveClientEventType.SESSION_INPUT_AUDIO_MUTE # type: ignore -class MCPToolboxTool(ToolboxTool, discriminator="mcp"): # pylint: disable=docstring-keyword-should-match-keyword-only - """An MCP tool stored in a toolbox. +class LiveClientEventLiveInputAudioUnmuteParam( + LiveClientEvent, discriminator="session.input_audio.unmute" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Resume audio input to a Live model after muting it. The server acknowledges with + ``session.input_audio.unmuted``. An active audio fixture still pauses inference until playback + finishes. - :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 type: 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``, ``connector_id``, or - ``tunnel_id`` must be provided. - :vartype server_url: str - :ivar connector_id: Identifier for service connectors, like those available in ChatGPT. One of - ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. Learn more about service - connectors `here `_. Currently supported - ``connector_id`` values are: + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.input_audio.unmute``. Required. + SESSION_INPUT_AUDIO_UNMUTE. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_AUDIO_UNMUTE + """ - * 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"] + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_INPUT_AUDIO_UNMUTE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.input_audio.unmute``. Required. + SESSION_INPUT_AUDIO_UNMUTE.""" - :vartype connector_id: str or str or str or str or str or str or str or str - :ivar tunnel_id: The Secure MCP Tunnel ID to use instead of a direct server URL. One of - ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. - :vartype tunnel_id: 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 allowed_callers: - :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] - :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 defer_loading: Whether this MCP tool is deferred and discovered via tool search. - :vartype defer_loading: bool - :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 + @overload + def __init__( + self, + *, + event_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 = LiveClientEventType.SESSION_INPUT_AUDIO_UNMUTE # type: ignore + + +class LiveClientEventLiveInstructionsAppendParam( + LiveClientEvent, discriminator="session.instructions.append" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Append developer instructions to the Live conversation while it is running, optionally + associating them with an existing client delegation. Rejected while an audio fixture is active. + These instructions remain in conversation history through compaction and are included in future + backend delegations. For external audio, describe content already delivered so the assistant + does not repeat it. + + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.instructions.append``. Required. + SESSION_INSTRUCTIONS_APPEND. + :vartype type: str or ~azure.ai.projects.models.SESSION_INSTRUCTIONS_APPEND + :ivar delegation_id: Required. + :vartype delegation_id: str + :ivar content: Instruction text to append, limited to 500 tokens. This is a plain string, not + an array of content parts. Required. + :vartype content: str """ - type: Literal[ToolboxToolType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """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``, ``connector_id``, or ``tunnel_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``, - ``connector_id``, or ``tunnel_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\"]""" - tunnel_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Secure MCP Tunnel ID to use instead of a direct server URL. One of ``server_url``, - ``connector_id``, or ``tunnel_id`` must be provided.""" - 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.""" - allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - 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\"]""" - defer_loading: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether this MCP tool is deferred and discovered via tool search.""" - 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.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_INSTRUCTIONS_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.instructions.append``. Required. + SESSION_INSTRUCTIONS_APPEND.""" + delegation_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + content: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Instruction text to append, limited to 500 tokens. This is a plain string, not an array of + content parts. Required.""" @overload def __init__( self, *, - server_label: str, - name: Optional[str] = None, - description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, - 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, - tunnel_id: Optional[str] = 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, - allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = None, - require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = None, - defer_loading: Optional[bool] = None, - project_connection_id: Optional[str] = None, + delegation_id: str, + content: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14051,35 +14524,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolboxToolType.MCP # type: ignore + self.type = LiveClientEventType.SESSION_INSTRUCTIONS_APPEND # type: ignore -class MCPToolFilter(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """MCP tool filter. +class LiveClientEventLiveOutputAudioFixturePlayParam( + LiveClientEvent, discriminator="session.output_audio.fixture.play" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Play one complete audio fixture through the session output. Send this event over the primary + WebSocket or a server sideband. Audio must be raw mono PCM16 little-endian at 24 kHz, + regardless of the session audio format, and at most 30 seconds. The entire payload is validated + before model speech is interrupted and input is muted. Only one fixture can be active. + fixture.playing acknowledges acceptance and fixture.played reports server mixer drain. These + notifications are not exact transport-media boundaries. Input arriving during playback is + dropped and not replayed. - :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 event_id: + :vartype event_id: str + :ivar type: Required. SESSION_OUTPUT_AUDIO_FIXTURE_PLAY. + :vartype type: str or ~azure.ai.projects.models.SESSION_OUTPUT_AUDIO_FIXTURE_PLAY + :ivar audio: Base64-encoded raw mono PCM16 audio, little-endian, at 24 kHz. Do not include a + WAV or other container header. Required. + :vartype audio: str """ - 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.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAY] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. SESSION_OUTPUT_AUDIO_FIXTURE_PLAY.""" + audio: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64-encoded raw mono PCM16 audio, little-endian, at 24 kHz. Do not include a WAV or other + container header. Required.""" @overload def __init__( self, *, - tool_names: Optional[list[str]] = None, - read_only: Optional[bool] = None, + audio: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14091,26 +14571,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveClientEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAY # type: ignore -class MCPToolRequireApproval(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """MCPToolRequireApproval. +class LiveClientEventLiveResponseCreateParam( + LiveClientEvent, discriminator="response.create" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Request a response from the Live session’s Responses backend, or continue a delegated response + waiting for tool results. Requires Responses delegation. - :ivar always: - :vartype always: ~azure.ai.projects.models.MCPToolFilter - :ivar never: - :vartype never: ~azure.ai.projects.models.MCPToolFilter + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``response.create``. Required. RESPONSE_CREATE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_CREATE """ - always: Optional["_models.MCPToolFilter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - never: Optional["_models.MCPToolFilter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.RESPONSE_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``response.create``. Required. RESPONSE_CREATE.""" @overload def __init__( self, *, - always: Optional["_models.MCPToolFilter"] = None, - never: Optional["_models.MCPToolFilter"] = None, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14122,32 +14606,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveClientEventType.RESPONSE_CREATE # type: ignore -class MemoryOperation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Represents a single memory operation (create, update, or delete) performed on a memory item. +class LiveClientEventLiveResponseItemCreateParam( + LiveClientEvent, discriminator="response.item.create" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Add an input item to the Live session’s Responses backend. Requires Responses delegation; use + ``response.create`` to request a response. - :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 event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``response.item.create``. Required. + RESPONSE_ITEM_CREATE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_ITEM_CREATE + :ivar item: An input item to append to the Responses backend conversation, such as a user + message or a function tool result. Required. + :vartype item: dict[str, any] """ - kind: Union[str, "_models.MemoryOperationKind"] = 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.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.RESPONSE_ITEM_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``response.item.create``. Required. RESPONSE_ITEM_CREATE.""" + item: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An input item to append to the Responses backend conversation, such as a user message or a + function tool result. Required.""" @overload def __init__( self, *, - kind: Union[str, "_models.MemoryOperationKind"], - memory_item: "_models.MemoryItem", + item: dict[str, Any], + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14159,23 +14649,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveClientEventType.RESPONSE_ITEM_CREATE # type: ignore -class MemorySearchItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A retrieved memory item from memory search. +class LiveClientEventLiveSessionCloseParam( + LiveClientEvent, discriminator="session.close" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Request that the Live session close. The terminal ``session.closed`` event contains the close + reason and final usage. - :ivar memory_item: Retrieved memory item. Required. - :vartype memory_item: ~azure.ai.projects.models.MemoryItem + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.close``. Required. SESSION_CLOSE. + :vartype type: str or ~azure.ai.projects.models.SESSION_CLOSE """ - memory_item: "_models.MemoryItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Retrieved memory item. Required.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_CLOSE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.close``. Required. SESSION_CLOSE.""" @overload def __init__( self, *, - memory_item: "_models.MemoryItem", + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14187,23 +14684,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveClientEventType.SESSION_CLOSE # type: ignore -class MemorySearchOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Memory search options. +class LiveClientEventLiveSessionUpdateParam( + LiveClientEvent, discriminator="session.update" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Update the delegation settings or transcript triggers of an active Live session. The server + acknowledges accepted changes with ``session.updated``. - :ivar max_memories: Maximum number of memory items to return. - :vartype max_memories: int + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.update``. Required. SESSION_UPDATE. + :vartype type: str or ~azure.ai.projects.models.SESSION_UPDATE + :ivar session: Sparse delegation and trigger updates. Omitted settings retain their values. The + delegation type cannot change. Model, frontend instructions, audio, and startup input are + immutable. Required. + :vartype session: ~azure.ai.projects.models.LiveSessionUpdateParams """ - max_memories: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of memory items to return.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_UPDATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.update``. Required. SESSION_UPDATE.""" + session: "_models.LiveSessionUpdateParams" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Sparse delegation and trigger updates. Omitted settings retain their values. The delegation + type cannot change. Model, frontend instructions, audio, and startup input are immutable. + Required.""" @overload def __init__( self, *, - max_memories: Optional[int] = None, + session: "_models.LiveSessionUpdateParams", + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14215,52 +14728,45 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveClientEventType.SESSION_UPDATE # type: ignore -class MemorySearchPreviewTool( - Tool, discriminator="memory_search_preview" +class LiveClientEventLiveThinkingAppendParam( + LiveClientEvent, discriminator="session.thinking.append" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A tool for integrating memories into the agent. + """Provide silent reasoning or progress context to the Live model, optionally for an existing + client delegation. Rejected while an audio fixture is active. - :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 event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.thinking.append``. Required. + SESSION_THINKING_APPEND. + :vartype type: str or ~azure.ai.projects.models.SESSION_THINKING_APPEND + :ivar delegation_id: Required. + :vartype delegation_id: str + :ivar content: Silent reasoning or progress context, limited to 500 tokens. It does not + directly request speech, but can influence later speech and is not a secrecy boundary. + Required. + :vartype content: 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.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_THINKING_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.thinking.append``. Required. + SESSION_THINKING_APPEND.""" + delegation_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + content: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Silent reasoning or progress context, limited to 500 tokens. It does not directly request + speech, but can influence later speech and is not a secrecy boundary. Required.""" @overload def __init__( self, *, - memory_store_name: str, - scope: str, - search_options: Optional["_models.MemorySearchOptions"] = None, - update_delay: Optional[int] = None, + delegation_id: str, + content: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -14272,28 +14778,76 @@ 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 + self.type = LiveClientEventType.SESSION_THINKING_APPEND # type: ignore -class MemoryStoreDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Base definition for memory store configurations. +class LiveCodeInterpreterToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveCodeInterpreterToolInputParam. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - MemoryStoreDefaultDefinition + :ivar type: Required. Default value is "code_interpreter". + :vartype type: str + """ - :ivar kind: The kind of the memory store. Required. "default" - :vartype kind: str or ~azure.ai.projects.models.MemoryStoreKind + type: Literal["code_interpreter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"code_interpreter\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["code_interpreter"] = "code_interpreter" + + +class LiveComputerToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveComputerToolInputParam. + + :ivar type: Required. Default value is "computer". + :vartype type: 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["computer"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"computer\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["computer"] = "computer" + + +class LiveContainerNetworkPolicyDisabledParam(_Model): # pylint: disable=docstring-missing-param + """LiveContainerNetworkPolicyDisabledParam. + + :ivar type: Disable outbound network access. Always ``disabled``. Required. Default value is + "disabled". + :vartype type: str + """ + + type: Literal["disabled"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Disable outbound network access. Always ``disabled``. Required. Default value is \"disabled\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["disabled"] = "disabled" + + +class LiveContainerReferenceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveContainerReferenceParam. + + :ivar type: References a container created with the /v1/containers endpoint. Required. Default + value is "container_reference". + :vartype type: str + :ivar container_id: The ID of the referenced container. Required. + :vartype container_id: str + """ + + type: Literal["container_reference"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """References a container created with the /v1/containers endpoint. Required. Default value is + \"container_reference\".""" + container_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the referenced container. Required.""" @overload def __init__( self, *, - kind: str, + container_id: str, ) -> None: ... @overload @@ -14305,42 +14859,27 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["container_reference"] = "container_reference" -class MemoryStoreDefaultDefinition( - MemoryStoreDefinition, discriminator="default" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Default memory store implementation. +class LiveContextWindowUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The latest measured context-window usage of the Live model. This is separate from billing usage + and delegated Responses token usage. - :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 usage_ratio: The latest active context token count divided by the Live model context + limit. Can decrease after compaction and may lag between measured audio frames. Required. + :vartype usage_ratio: float """ - 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.""" + usage_ratio: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The latest active context token count divided by the Live model context limit. Can decrease + after compaction and may lag between measured audio frames. Required.""" @overload def __init__( self, *, - chat_model: str, - embedding_model: str, - options: Optional["_models.MemoryStoreDefaultOptions"] = None, + usage_ratio: float, ) -> None: ... @overload @@ -14352,53 +14891,38 @@ 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): # pylint: disable=docstring-keyword-should-match-keyword-only - """Default memory store configurations. +class LiveCustomToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveCustomToolInputParam. - :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. - The service defaults to ``true`` if a value is not specified by the caller. - :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: ~datetime.timedelta + :ivar type: Required. Default value is "custom". + :vartype type: str """ - 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. The service defaults to ``true`` if - a value is not specified by the caller.""" - default_ttl_seconds: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" - ) - """The default time-to-live for memories in seconds. A value of ``0`` indicates that memories do - not expire. Defaults to ``0``.""" + type: Literal["custom"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"custom\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["custom"] = "custom" + + +class LiveCustomVoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveCustomVoiceParam. + + :ivar id: Required. + :vartype id: str + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - user_profile_enabled: bool, - chat_summary_enabled: bool, - user_profile_details: Optional[str] = None, - procedural_memory_enabled: Optional[bool] = None, - default_ttl_seconds: Optional[datetime.timedelta] = None, + id: str, # pylint: disable=redefined-builtin ) -> None: ... @overload @@ -14412,39 +14936,43 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreDeleteScopeResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Response for deleting memories from a scope. +class LiveDataChannelConfigParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Control which Live events an untrusted WebRTC frontend can send and receive over its data + channel. These restrictions do not apply to trusted sideband connections. - :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 allowed_client_events: Client event types that the frontend data channel may send. Use + 'all' to allow every client event; an empty array allows none. Omission preserves the existing + allow-all behavior. Is either a Literal["all"] type or a [str] type. + :vartype allowed_client_events: str or list[str] + :ivar allowed_server_events: Server events that may be sent to the frontend data channel. Use + 'all' to allow every server event; an empty array allows none. Omission preserves the existing + allow-all behavior. Responses events use an object with type 'response.event' and a + response_event selector. Is either a Literal["all"] type or a [LiveAllowedServerEventParam] + type. + :vartype allowed_server_events: str or + list[~azure.ai.projects.models.LiveAllowedServerEventParam] """ - object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED] = rest_field( + allowed_client_events: Optional[Union[Literal["all"], list[str]]] = 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.""" + """Client event types that the frontend data channel may send. Use 'all' to allow every client + event; an empty array allows none. Omission preserves the existing allow-all behavior. Is + either a Literal[\"all\"] type or a [str] type.""" + allowed_server_events: Optional[Union[Literal["all"], list["_models.LiveAllowedServerEventParam"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Server events that may be sent to the frontend data channel. Use 'all' to allow every server + event; an empty array allows none. Omission preserves the existing allow-all behavior. + Responses events use an object with type 'response.event' and a response_event selector. Is + either a Literal[\"all\"] type or a [LiveAllowedServerEventParam] type.""" @overload def __init__( self, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED], - name: str, - scope: str, - deleted: bool, + allowed_client_events: Optional[Union[Literal["all"], list[str]]] = None, + allowed_server_events: Optional[Union[Literal["all"], list["_models.LiveAllowedServerEventParam"]]] = None, ) -> None: ... @overload @@ -14458,63 +14986,25 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A memory store that can store and retrieve user memories. +class LiveDecisionChoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionChoiceParam. - :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. + :ivar value: Required. Is either a str type or a bool type. + :vartype value: str or bool + :ivar description: :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 """ - 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" - ) - """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.""" + value: Union[str, bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a str type or a bool type.""" 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, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE], - id: str, # pylint: disable=redefined-builtin - created_at: datetime.datetime, - updated_at: datetime.datetime, - name: str, - definition: "_models.MemoryStoreDefinition", + value: Union[str, bool], description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -14528,50 +15018,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreOperationUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Usage statistics of a memory store operation. +class LiveDecisionQuestion(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionQuestion. - :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 + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveDecisionChoiceQuestionParam, LiveDecisionPredicateQuestionParam, + LiveDecisionScoreQuestionParam + + :ivar type: Required. Known values are: "choice", "predicate", and "score". + :vartype type: str or ~azure.ai.projects.models.LiveDecisionQuestionType """ - 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.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"choice\", \"predicate\", and \"score\".""" @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, + type: str, ) -> None: ... @overload @@ -14585,33 +15051,61 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MemoryStoreSearchResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Memory search response. - - :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 - """ +class LiveDecisionChoiceQuestionParam( + LiveDecisionQuestion, discriminator="choice" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionChoiceQuestionParam. - 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.""" + :ivar type: Required. CHOICE. + :vartype type: str or ~azure.ai.projects.models.CHOICE + :ivar name: + :vartype name: str + :ivar instructions: Required. Is either a str type or a + [Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam"]] type. + :vartype instructions: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam or + ~azure.ai.projects.models.LiveDecisionInputJsonParam] + :ivar choices: Required. + :vartype choices: list[~azure.ai.projects.models.LiveDecisionChoiceParam] + """ + + type: Literal[LiveDecisionQuestionType.CHOICE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. CHOICE.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + instructions: Union[ + str, + list[ + Union[ + "_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam", + ] + ], + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\", \"_models.LiveDecisionInputJsonParam\"]] type.""" + choices: list["_models.LiveDecisionChoiceParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" @overload def __init__( self, *, - search_id: str, - memories: list["_models.MemorySearchItem"], - usage: "_models.MemoryStoreOperationUsage", + instructions: Union[ + str, + list[ + Union[ + "_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam", + ] + ], + ], + choices: list["_models.LiveDecisionChoiceParam"], + name: Optional[str] = None, ) -> None: ... @overload @@ -14623,31 +15117,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionQuestionType.CHOICE # type: ignore -class MemoryStoreUpdateCompletedResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Memory update result. +class LiveDecisionCompleted(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionCompleted. - :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: Required. Default value is "decision.completed". + :vartype type: str + :ivar decision: The native Decision API response, including its model, ordered answers, and + token usage. Required. + :vartype decision: ~azure.ai.projects.models.DecisionResponse """ - 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["decision.completed"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"decision.completed\".""" + decision: "_models.DecisionResponse" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The native Decision API response, including its model, ordered answers, and token usage. + Required.""" @overload def __init__( self, *, - memory_operations: list["_models.MemoryOperation"], - usage: "_models.MemoryStoreOperationUsage", + decision: "_models.DecisionResponse", ) -> None: ... @overload @@ -14659,53 +15152,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["decision.completed"] = "decision.completed" -class MemoryStoreUpdateResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Provides the status of a memory store update operation. +class LiveDecisionInputItemParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionInputItemParam. - :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 + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveDecisionCustomToolCallParam, LiveDecisionCustomToolCallOutputParam, + LiveDecisionFunctionCallParam, LiveDecisionFunctionCallOutputParam, + LiveDecisionInputItemParamMessage + + :ivar type: Required. Known values are: "message", "function_call", "function_call_output", + "custom_tool_call", and "custom_tool_call_output". + :vartype type: str or ~azure.ai.projects.models.LiveDecisionInputItemParamType """ - 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\".""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"message\", \"function_call\", \"function_call_output\", + \"custom_tool_call\", and \"custom_tool_call_output\".""" @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, + type: str, ) -> None: ... @overload @@ -14719,37 +15191,108 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Metadata(_Model): - """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. +class LiveDecisionCustomToolCallOutputParam( + LiveDecisionInputItemParam, discriminator="custom_tool_call_output" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionCustomToolCallOutputParam. + :ivar id: + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: Required. CUSTOM_TOOL_CALL_OUTPUT. + :vartype type: str or ~azure.ai.projects.models.CUSTOM_TOOL_CALL_OUTPUT + :ivar output: Required. Is either a str type or a [Union["_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam"]] type. + :vartype output: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam] """ + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionInputItemParamType.CUSTOM_TOOL_CALL_OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. CUSTOM_TOOL_CALL_OUTPUT.""" + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) + ) + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\"]] type.""" -class Microsoft365PermissionScopes(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A set of delegated permission scopes requested from a single resource application. + @overload + def __init__( + self, + *, + call_id: str, + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]], + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, + ) -> None: ... - :ivar resource_app_id: Application id of the resource that exposes the requested delegated - scopes. Required. - :vartype resource_app_id: str - :ivar scopes: Delegated scope names requested from the resource application. Must not be empty. - Required. - :vartype scopes: list[str] + @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 = LiveDecisionInputItemParamType.CUSTOM_TOOL_CALL_OUTPUT # type: ignore + + +class LiveDecisionCustomToolCallParam( + LiveDecisionInputItemParam, discriminator="custom_tool_call" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionCustomToolCallParam. + + :ivar id: + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: The item type. Always ``custom_tool_call``. Required. CUSTOM_TOOL_CALL. + :vartype type: str or ~azure.ai.projects.models.CUSTOM_TOOL_CALL + :ivar name: The name of the custom tool to call. Required. + :vartype name: str + :ivar namespace: + :vartype namespace: str + :ivar input: The input to the custom tool call. Required. + :vartype input: str """ - resource_app_id: str = rest_field(name="resourceAppId", visibility=["read", "create", "update", "delete", "query"]) - """Application id of the resource that exposes the requested delegated scopes. Required.""" - scopes: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Delegated scope names requested from the resource application. Must not be empty. Required.""" + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionInputItemParamType.CUSTOM_TOOL_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The item type. Always ``custom_tool_call``. Required. CUSTOM_TOOL_CALL.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the custom tool to call. Required.""" + namespace: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The input to the custom tool call. Required.""" @overload def __init__( self, *, - resource_app_id: str, - scopes: list[str], + call_id: str, + name: str, + input: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, + namespace: Optional[str] = None, ) -> None: ... @overload @@ -14761,125 +15304,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionInputItemParamType.CUSTOM_TOOL_CALL # type: ignore -class Microsoft365PublishDefaults(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Default and previously-published values used to pre-populate a Microsoft 365 publish request - for a Foundry agent. +class LiveDecisionFunctionCallOutputParam( + LiveDecisionInputItemParam, discriminator="function_call_output" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionFunctionCallOutputParam. - :ivar app_publish_scope: The publish scope. Known values are: "Personal", "Shared", and - "Tenant". - :vartype app_publish_scope: str or ~azure.ai.projects.models.Microsoft365PublishScope - :ivar agent_name: The agent name. - :vartype agent_name: str - :ivar agent_display_name: The user-facing display name for the agent. Defaults to the agent - name if not previously overridden. - :vartype agent_display_name: str - :ivar app_registration_client_id: The app-registration client id associated with the agent. - :vartype app_registration_client_id: str - :ivar bot_service_arm_id: ARM resource id of the Azure Bot Service associated with the - previously-published app, if any. - :vartype bot_service_arm_id: str - :ivar app_version: The most recently published app version. - :vartype app_version: str - :ivar recommended_next_app_version: The recommended next app version (the most recent app - version, incremented). - :vartype recommended_next_app_version: str - :ivar title_id: The Microsoft 365 title id of the previously-published app, if any. - :vartype title_id: str - :ivar teams_app_id: The Microsoft Teams app id of the previously-published app, if any. - :vartype teams_app_id: str - :ivar short_description: Short, one-line description shown in the Teams app listing. - :vartype short_description: str - :ivar full_description: Full description shown on the Teams app details page. - :vartype full_description: str - :ivar developer_name: Display name of the developer / publisher. - :vartype developer_name: str - :ivar developer_website_url: Developer / publisher website URL. - :vartype developer_website_url: str - :ivar privacy_url: Privacy policy URL. - :vartype privacy_url: str - :ivar terms_of_use_url: Terms-of-use URL. - :vartype terms_of_use_url: str + :ivar id: + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: The type of the function tool call output. Always ``function_call_output``. + Required. FUNCTION_CALL_OUTPUT. + :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL_OUTPUT + :ivar output: Required. Is either a str type or a [Union["_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam"]] type. + :vartype output: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam] """ - app_publish_scope: Optional[Union[str, "_models.Microsoft365PublishScope"]] = rest_field( - name="appPublishScope", visibility=["read", "create", "update", "delete", "query"] - ) - """The publish scope. Known values are: \"Personal\", \"Shared\", and \"Tenant\".""" - agent_name: Optional[str] = rest_field(name="agentName", visibility=["read", "create", "update", "delete", "query"]) - """The agent name.""" - agent_display_name: Optional[str] = rest_field( - name="agentDisplayName", visibility=["read", "create", "update", "delete", "query"] - ) - """The user-facing display name for the agent. Defaults to the agent name if not previously - overridden.""" - app_registration_client_id: Optional[str] = rest_field( - name="appRegistrationClientId", visibility=["read", "create", "update", "delete", "query"] - ) - """The app-registration client id associated with the agent.""" - bot_service_arm_id: Optional[str] = rest_field( - name="botServiceArmId", visibility=["read", "create", "update", "delete", "query"] - ) - """ARM resource id of the Azure Bot Service associated with the previously-published app, if any.""" - app_version: Optional[str] = rest_field( - name="appVersion", visibility=["read", "create", "update", "delete", "query"] - ) - """The most recently published app version.""" - recommended_next_app_version: Optional[str] = rest_field( - name="recommendedNextAppVersion", visibility=["read", "create", "update", "delete", "query"] - ) - """The recommended next app version (the most recent app version, incremented).""" - title_id: Optional[str] = rest_field(name="titleId", visibility=["read", "create", "update", "delete", "query"]) - """The Microsoft 365 title id of the previously-published app, if any.""" - teams_app_id: Optional[str] = rest_field( - name="teamsAppId", visibility=["read", "create", "update", "delete", "query"] - ) - """The Microsoft Teams app id of the previously-published app, if any.""" - short_description: Optional[str] = rest_field( - name="shortDescription", visibility=["read", "create", "update", "delete", "query"] - ) - """Short, one-line description shown in the Teams app listing.""" - full_description: Optional[str] = rest_field( - name="fullDescription", visibility=["read", "create", "update", "delete", "query"] - ) - """Full description shown on the Teams app details page.""" - developer_name: Optional[str] = rest_field( - name="developerName", visibility=["read", "create", "update", "delete", "query"] - ) - """Display name of the developer / publisher.""" - developer_website_url: Optional[str] = rest_field( - name="developerWebsiteUrl", visibility=["read", "create", "update", "delete", "query"] - ) - """Developer / publisher website URL.""" - privacy_url: Optional[str] = rest_field( - name="privacyUrl", visibility=["read", "create", "update", "delete", "query"] + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Privacy policy URL.""" - terms_of_use_url: Optional[str] = rest_field( - name="termsOfUseUrl", visibility=["read", "create", "update", "delete", "query"] + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionInputItemParamType.FUNCTION_CALL_OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the function tool call output. Always ``function_call_output``. Required. + FUNCTION_CALL_OUTPUT.""" + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) ) - """Terms-of-use URL.""" + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\"]] type.""" @overload def __init__( self, *, - app_publish_scope: Optional[Union[str, "_models.Microsoft365PublishScope"]] = None, - agent_name: Optional[str] = None, - agent_display_name: Optional[str] = None, - app_registration_client_id: Optional[str] = None, - bot_service_arm_id: Optional[str] = None, - app_version: Optional[str] = None, - recommended_next_app_version: Optional[str] = None, - title_id: Optional[str] = None, - teams_app_id: Optional[str] = None, - short_description: Optional[str] = None, - full_description: Optional[str] = None, - developer_name: Optional[str] = None, - developer_website_url: Optional[str] = None, - privacy_url: Optional[str] = None, - terms_of_use_url: Optional[str] = None, + call_id: str, + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]], + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, ) -> None: ... @overload @@ -14891,30 +15362,55 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionInputItemParamType.FUNCTION_CALL_OUTPUT # type: ignore -class Microsoft365PublishResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Response from publishing an agent to Microsoft 365 / Microsoft Teams. +class LiveDecisionFunctionCallParam( + LiveDecisionInputItemParam, discriminator="function_call" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionFunctionCallParam. - :ivar title_id: The Microsoft 365 title id of the published app. - :vartype title_id: str - :ivar teams_app_id: The Microsoft Teams app id of the published app. - :vartype teams_app_id: str + :ivar id: + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: The item type. Always ``function_call``. Required. FUNCTION_CALL. + :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL + :ivar name: Required. + :vartype name: str + :ivar namespace: + :vartype namespace: str + :ivar arguments: The function arguments as a JSON string. Required. + :vartype arguments: str """ - title_id: Optional[str] = rest_field(name="titleId", visibility=["read", "create", "update", "delete", "query"]) - """The Microsoft 365 title id of the published app.""" - teams_app_id: Optional[str] = rest_field( - name="teamsAppId", visibility=["read", "create", "update", "delete", "query"] + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The Microsoft Teams app id of the published app.""" + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionInputItemParamType.FUNCTION_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The item type. Always ``function_call``. Required. FUNCTION_CALL.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + namespace: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The function arguments as a JSON string. Required.""" @overload def __init__( self, *, - title_id: Optional[str] = None, - teams_app_id: Optional[str] = None, + call_id: str, + name: str, + arguments: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, + namespace: Optional[str] = None, ) -> None: ... @overload @@ -14926,23 +15422,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionInputItemParamType.FUNCTION_CALL # type: ignore -class MicrosoftCopilotHarness(AgentHarness, discriminator="microsoft_copilot_preview"): - """The Microsoft Copilot managed harness for prompt agents. +class LiveDecisionInputImageParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionInputImageParam. - :ivar type: The type of managed harness. Always ``microsoft_copilot_preview``. Required. - Default value is "microsoft_copilot_preview". + :ivar type: Required. Default value is "input_image". :vartype type: str + :ivar image_url: A base64-encoded image data URL or a publicly accessible HTTP(S) image URL. + Required. + :vartype image_url: str + :ivar detail: Known values are: "low", "high", "auto", and "original". + :vartype detail: str or ~azure.ai.projects.models.LiveDetailEnum """ - type: Literal["microsoft_copilot_preview"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of managed harness. Always ``microsoft_copilot_preview``. Required. Default value is - \"microsoft_copilot_preview\".""" + type: Literal["input_image"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"input_image\".""" + image_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A base64-encoded image data URL or a publicly accessible HTTP(S) image URL. Required.""" + detail: Optional[Union[str, "_models.LiveDetailEnum"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"low\", \"high\", \"auto\", and \"original\".""" @overload def __init__( self, + *, + image_url: str, + detail: Optional[Union[str, "_models.LiveDetailEnum"]] = None, ) -> None: ... @overload @@ -14954,33 +15463,22 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "microsoft_copilot_preview" # type: ignore + self.type: Literal["input_image"] = "input_image" -class MicrosoftCopilotToolsetConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """An enablement override for a Microsoft Copilot built-in tool. +class LiveDecisionInputItemParamMessage(LiveDecisionInputItemParam, discriminator="message"): + """LiveDecisionInputItemParamMessage. - :ivar name: The built-in tool to configure. Required. Known values are: "filesystem_read", - "filesystem_write", "shell", "web", and "subagents". - :vartype name: str or ~azure.ai.projects.models.MicrosoftCopilotBuiltInTool - :ivar enabled: Whether the built-in tool is enabled. If omitted, the toolset default applies. - :vartype enabled: bool + :ivar type: Required. MESSAGE. + :vartype type: str or ~azure.ai.projects.models.MESSAGE """ - name: Union[str, "_models.MicrosoftCopilotBuiltInTool"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The built-in tool to configure. Required. Known values are: \"filesystem_read\", - \"filesystem_write\", \"shell\", \"web\", and \"subagents\".""" - enabled: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the built-in tool is enabled. If omitted, the toolset default applies.""" + type: Literal[LiveDecisionInputItemParamType.MESSAGE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. MESSAGE.""" @overload def __init__( self, - *, - name: Union[str, "_models.MicrosoftCopilotBuiltInTool"], - enabled: Optional[bool] = None, ) -> None: ... @overload @@ -14992,23 +15490,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionInputItemParamType.MESSAGE # type: ignore -class MicrosoftCopilotToolsetDefaultConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The default enablement setting for Microsoft Copilot built-in tools. +class LiveDecisionInputJsonParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionInputJsonParam. - :ivar enabled: Whether built-in tools are enabled by default. Defaults to true. - :vartype enabled: bool + :ivar type: Required. Default value is "input_json". + :vartype type: str + :ivar data: Required. Is either a LiveDecisionJsonObject type or a [LiveDecisionJsonObject] + type. + :vartype data: ~azure.ai.projects.models.LiveDecisionJsonObject or + list[~azure.ai.projects.models.LiveDecisionJsonObject] """ - enabled: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether built-in tools are enabled by default. Defaults to true.""" + type: Literal["input_json"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"input_json\".""" + data: Union["_models.LiveDecisionJsonObject", list["_models.LiveDecisionJsonObject"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required. Is either a LiveDecisionJsonObject type or a [LiveDecisionJsonObject] type.""" @overload def __init__( self, *, - enabled: Optional[bool] = None, + data: Union["_models.LiveDecisionJsonObject", list["_models.LiveDecisionJsonObject"]], ) -> None: ... @overload @@ -15020,42 +15527,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["input_json"] = "input_json" -class MicrosoftCopilotToolsetPreview( - Tool, discriminator="microsoft_copilot_toolset_preview" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Configuration overrides for Microsoft Copilot built-in tools. +class LiveDecisionInputTextParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionInputTextParam. - :ivar type: The type of the toolset. Always ``microsoft_copilot_toolset_preview``. Required. - MICROSOFT_COPILOT_TOOLSET_PREVIEW. - :vartype type: str or ~azure.ai.projects.models.MICROSOFT_COPILOT_TOOLSET_PREVIEW - :ivar default_config: The default configuration for built-in tools. If omitted, built-in tools - are enabled by default. - :vartype default_config: ~azure.ai.projects.models.MicrosoftCopilotToolsetDefaultConfig - :ivar configs: Per-tool configuration overrides. Duplicate built-in tool names are not allowed. - :vartype configs: list[~azure.ai.projects.models.MicrosoftCopilotToolsetConfig] + :ivar type: Required. Default value is "input_text". + :vartype type: str + :ivar text: The text input to the model. Required. + :vartype text: str """ - type: Literal[ToolType.MICROSOFT_COPILOT_TOOLSET_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the toolset. Always ``microsoft_copilot_toolset_preview``. Required. - MICROSOFT_COPILOT_TOOLSET_PREVIEW.""" - default_config: Optional["_models.MicrosoftCopilotToolsetDefaultConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The default configuration for built-in tools. If omitted, built-in tools are enabled by - default.""" - configs: Optional[list["_models.MicrosoftCopilotToolsetConfig"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Per-tool configuration overrides. Duplicate built-in tool names are not allowed.""" + type: Literal["input_text"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"input_text\".""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text input to the model. Required.""" @overload def __init__( self, *, - default_config: Optional["_models.MicrosoftCopilotToolsetDefaultConfig"] = None, - configs: Optional[list["_models.MicrosoftCopilotToolsetConfig"]] = None, + text: str, ) -> None: ... @overload @@ -15067,34 +15560,61 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.MICROSOFT_COPILOT_TOOLSET_PREVIEW # type: ignore + self.type: Literal["input_text"] = "input_text" -class MicrosoftFabricPreviewTool( - Tool, discriminator="fabric_dataagent_preview" +class LiveDecisionJsonObject(_Model): + """LiveDecisionJsonObject.""" + + +class LiveDecisionPredicateQuestionParam( + LiveDecisionQuestion, discriminator="predicate" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """The input definition information for a Microsoft Fabric tool as used to configure an agent. + """LiveDecisionPredicateQuestionParam. - :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 + :ivar type: Required. PREDICATE. + :vartype type: str or ~azure.ai.projects.models.PREDICATE + :ivar name: + :vartype name: str + :ivar instructions: Required. Is either a str type or a + [Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam"]] type. + :vartype instructions: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam or + ~azure.ai.projects.models.LiveDecisionInputJsonParam] """ - 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.""" + type: Literal[LiveDecisionQuestionType.PREDICATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. PREDICATE.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + instructions: Union[ + str, + list[ + Union[ + "_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam", + ] + ], + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\", \"_models.LiveDecisionInputJsonParam\"]] type.""" @overload def __init__( self, *, - fabric_dataagent_preview: "_models.FabricDataAgentToolParameters", + instructions: Union[ + str, + list[ + Union[ + "_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam", + ] + ], + ], + name: Optional[str] = None, ) -> None: ... @overload @@ -15106,42 +15626,26 @@ 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 + self.type = LiveDecisionQuestionType.PREDICATE # type: ignore -class MisalignmentErrorDetailsResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """MisalignmentErrorDetailsResource. +class LiveDecisionQuestionsInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Questions evaluated using the current transcript and the session's shared Decision items. - :ivar error_type: An optional classification; clients must accept additional values. Known - values are: "potentially_unintended_data_transfer", "potentially_unintended_data_access", - "potentially_unintended_destructive_activity", and "other". - :vartype error_type: str or ~azure.ai.projects.models.MisalignmentErrorType - :ivar detailed_explanation: The public explanation for this block. - :vartype detailed_explanation: str - :ivar steer: An optional public continuation instruction. - :vartype steer: ~azure.ai.projects.models.MisalignmentSteer + :ivar questions: Native Decision API questions evaluated together, in order. Required. + :vartype questions: list[~azure.ai.projects.models.LiveDecisionQuestion] """ - error_type: Optional[Union[str, "_models.MisalignmentErrorType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """An optional classification; clients must accept additional values. Known values are: - \"potentially_unintended_data_transfer\", \"potentially_unintended_data_access\", - \"potentially_unintended_destructive_activity\", and \"other\".""" - detailed_explanation: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The public explanation for this block.""" - steer: Optional["_models.MisalignmentSteer"] = rest_field( + questions: list["_models.LiveDecisionQuestion"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """An optional public continuation instruction.""" + """Native Decision API questions evaluated together, in order. Required.""" @overload def __init__( self, *, - error_type: Optional[Union[str, "_models.MisalignmentErrorType"]] = None, - detailed_explanation: Optional[str] = None, - steer: Optional["_models.MisalignmentSteer"] = None, + questions: list["_models.LiveDecisionQuestion"], ) -> None: ... @overload @@ -15155,21 +15659,25 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MisalignmentSteer(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """MisalignmentSteer. +class LiveDecisionScoreLevelParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionScoreLevelParam. - :ivar message: The public continuation instruction. Required. - :vartype message: str + :ivar label: Required. + :vartype label: str + :ivar description: + :vartype description: str """ - message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The public continuation instruction. Required.""" + label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - message: str, + label: str, + description: Optional[str] = None, ) -> None: ... @overload @@ -15183,21 +15691,61 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelCredentialRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Request to fetch credentials for a model asset. - - :ivar blob_uri: Blob URI of the model asset to fetch credentials for. Required. - :vartype blob_uri: str - """ +class LiveDecisionScoreQuestionParam( + LiveDecisionQuestion, discriminator="score" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionScoreQuestionParam. - blob_uri: str = rest_field(name="blobUri", visibility=["read", "create", "update", "delete", "query"]) - """Blob URI of the model asset to fetch credentials for. Required.""" + :ivar type: Required. SCORE. + :vartype type: str or ~azure.ai.projects.models.SCORE + :ivar name: + :vartype name: str + :ivar instructions: Required. Is either a str type or a + [Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam"]] type. + :vartype instructions: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam or + ~azure.ai.projects.models.LiveDecisionInputJsonParam] + :ivar levels: Required. + :vartype levels: list[~azure.ai.projects.models.LiveDecisionScoreLevelParam] + """ + + type: Literal[LiveDecisionQuestionType.SCORE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. SCORE.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + instructions: Union[ + str, + list[ + Union[ + "_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam", + ] + ], + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\", \"_models.LiveDecisionInputJsonParam\"]] type.""" + levels: list["_models.LiveDecisionScoreLevelParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" @overload def __init__( self, *, - blob_uri: str, + instructions: Union[ + str, + list[ + Union[ + "_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam", + "_models.LiveDecisionInputJsonParam", + ] + ], + ], + levels: list["_models.LiveDecisionScoreLevelParam"], + name: Optional[str] = None, ) -> None: ... @overload @@ -15209,47 +15757,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionQuestionType.SCORE # type: ignore -class ModelDeployment(Deployment, discriminator="ModelDeployment"): - """Model Deployment Definition. +class LiveSessionUpdateParamsDelegation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Delegation settings to update. The delegation type must match the current session; omitted + settings retain their values. - :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 + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveSessionUpdateParamsDelegationLiveClientDelegationParam, LiveDecisionsDelegationUpdateParam, + LiveResponsesDelegationUpdateParam + + :ivar type: Required. Known values are: "client", "responses", and "decisions". + :vartype type: str or ~azure.ai.projects.models.LiveSessionUpdateParamsDelegationType """ - 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.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"client\", \"responses\", and \"decisions\".""" @overload def __init__( self, + *, + type: str, ) -> None: ... @overload @@ -15261,44 +15792,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 ModelDeploymentSku(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Sku information. +class LiveDecisionsDelegationUpdateParam( + LiveSessionUpdateParamsDelegation, discriminator="decisions" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionsDelegationUpdateParam. - :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 + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: Required. DECISIONS. + :vartype type: str or ~azure.ai.projects.models.DECISIONS + :ivar decisions: + :vartype decisions: ~azure.ai.projects.models.LiveDecisionsSettingsUpdateParam """ - 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.""" + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + type: Literal[LiveSessionUpdateParamsDelegationType.DECISIONS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISIONS.""" + decisions: Optional["_models.LiveDecisionsSettingsUpdateParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) @overload def __init__( self, *, - capacity: int, - family: str, - name: str, - size: str, - tier: str, + acknowledgement_delay_ms: Optional[int] = None, + decisions: Optional["_models.LiveDecisionsSettingsUpdateParam"] = None, ) -> None: ... @overload @@ -15310,42 +15841,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveSessionUpdateParamsDelegationType.DECISIONS # type: ignore -class ModelPendingUploadRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Represents a request for a pending upload of a model version. +class LiveDecisionsSettingsInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionsSettingsInputParam. - :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 + :ivar questions: Native Decision API questions evaluated together, in order. Required. + :vartype questions: list[~azure.ai.projects.models.LiveDecisionQuestion] + :ivar model: Required. + :vartype model: str """ - 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"] + questions: list["_models.LiveDecisionQuestion"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The type of pending upload. Only TemporaryBlobReference is supported for models. Required. - Temporary blob reference.""" + """Native Decision API questions evaluated together, in order. Required.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], - pending_upload_id: Optional[str] = None, - connection_name: Optional[str] = None, + questions: list["_models.LiveDecisionQuestion"], + model: str, ) -> None: ... @overload @@ -15359,45 +15879,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelPendingUploadResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Represents the response for a model pending upload request. +class LiveDecisionsSettingsUpdateParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionsSettingsUpdateParam. - :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 + :ivar model: + :vartype model: str + :ivar questions: Native Decision API questions evaluated together, in order. + :vartype questions: list[~azure.ai.projects.models.LiveDecisionQuestion] """ - blob_reference: "_models.BlobReference" = rest_field( - name="blobReference", visibility=["read", "create", "update", "delete", "query"] - ) - """Container-level read, write, list SAS. Required.""" - pending_upload_id: str = rest_field( - name="pendingUploadId", visibility=["read", "create", "update", "delete", "query"] - ) - """ID for this upload request. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Version of asset to be created if user did not specify version when initially creating upload.""" - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( - name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + questions: Optional[list["_models.LiveDecisionQuestion"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The type of pending upload. Only TemporaryBlobReference is supported for models. Required. - Temporary blob reference.""" + """Native Decision API questions evaluated together, in order.""" @overload def __init__( self, *, - blob_reference: "_models.BlobReference", - pending_upload_id: str, - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], - version: Optional[str] = None, + model: Optional[str] = None, + questions: Optional[list["_models.LiveDecisionQuestion"]] = None, ) -> None: ... @overload @@ -15411,37 +15913,29 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelSamplingParams(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Represents a set of parameters used to control the sampling behavior of a language model during - text generation. +class LiveDecisionStoredInputItemParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionStoredInputItemParam. - :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 + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveDecisionStoredCustomToolCallParam, LiveDecisionStoredCustomToolCallOutputParam, + LiveDecisionStoredFunctionCallParam, LiveDecisionStoredFunctionCallOutputParam, + LiveDecisionStoredInputItemParamMessage + + :ivar type: Required. Known values are: "message", "function_call", "function_call_output", + "custom_tool_call", and "custom_tool_call_output". + :vartype type: str or ~azure.ai.projects.models.LiveDecisionStoredInputItemParamType """ - 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.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"message\", \"function_call\", \"function_call_output\", + \"custom_tool_call\", and \"custom_tool_call_output\".""" @overload def __init__( self, *, - temperature: Optional[float] = None, - top_p: Optional[float] = None, - seed: Optional[int] = None, - max_completion_tokens: Optional[int] = None, + type: str, ) -> None: ... @overload @@ -15455,29 +15949,49 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelSourceData(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Source information for the model. +class LiveDecisionStoredCustomToolCallOutputParam( + LiveDecisionStoredInputItemParam, discriminator="custom_tool_call_output" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """LiveDecisionStoredCustomToolCallOutputParam. - :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 + :ivar id: Required. + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: Required. CUSTOM_TOOL_CALL_OUTPUT. + :vartype type: str or ~azure.ai.projects.models.CUSTOM_TOOL_CALL_OUTPUT + :ivar output: Required. Is either a str type or a [Union["_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam"]] type. + :vartype output: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam] """ - source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = rest_field( - name="sourceType", visibility=["read", "create", "update", "delete", "query"] + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The source type of the model. Known values are: \"LocalUpload\" and \"TrainingJob\".""" - job_id: Optional[str] = rest_field(name="jobId", visibility=["read", "create", "update", "delete", "query"]) - """The job ID that produced this model.""" + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionStoredInputItemParamType.CUSTOM_TOOL_CALL_OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. CUSTOM_TOOL_CALL_OUTPUT.""" + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) + ) + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\"]] type.""" @overload def __init__( self, *, - source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = None, - job_id: Optional[str] = None, + id: str, # pylint: disable=redefined-builtin + call_id: str, + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]], + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, ) -> None: ... @overload @@ -15489,80 +16003,56 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionStoredInputItemParamType.CUSTOM_TOOL_CALL_OUTPUT # type: ignore -class ModelVersion(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Model Version Definition. +class LiveDecisionStoredCustomToolCallParam( + LiveDecisionStoredInputItemParam, discriminator="custom_tool_call" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionStoredCustomToolCallParam. - :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. + :ivar id: Required. :vartype id: str - :ivar name: The name of the resource. Required. + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: The item type. Always ``custom_tool_call``. Required. CUSTOM_TOOL_CALL. + :vartype type: str or ~azure.ai.projects.models.CUSTOM_TOOL_CALL + :ivar name: The name of the custom tool to call. 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 namespace: + :vartype namespace: str + :ivar input: The input to the custom tool call. Required. + :vartype input: str """ - 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"] + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + 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.""" + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionStoredInputItemParamType.CUSTOM_TOOL_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The item type. Always ``custom_tool_call``. Required. CUSTOM_TOOL_CALL.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the custom tool to call. Required.""" + namespace: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The input to the custom tool call. Required.""" @overload def __init__( self, *, - blob_uri: str, - weight_type: Optional[Union[str, "_models.FoundryModelWeightType"]] = None, - base_model: Optional[str] = None, - source: Optional["_models.ModelSourceData"] = None, - lora_config: Optional["_models.LoraConfig"] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + id: str, # pylint: disable=redefined-builtin + call_id: str, + name: str, + input: str, + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, + namespace: Optional[str] = None, ) -> None: ... @overload @@ -15574,31 +16064,54 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveDecisionStoredInputItemParamType.CUSTOM_TOOL_CALL # type: ignore -class MonthlyRecurrenceSchedule( - RecurrenceSchedule, discriminator="Monthly" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Monthly recurrence schedule. +class LiveDecisionStoredFunctionCallOutputParam( + LiveDecisionStoredInputItemParam, discriminator="function_call_output" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """LiveDecisionStoredFunctionCallOutputParam. - :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 id: Required. + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: The type of the function tool call output. Always ``function_call_output``. + Required. FUNCTION_CALL_OUTPUT. + :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL_OUTPUT + :ivar output: Required. Is either a str type or a [Union["_models.LiveDecisionInputTextParam", + "_models.LiveDecisionInputImageParam"]] type. + :vartype output: str or list[~azure.ai.projects.models.LiveDecisionInputTextParam or + ~azure.ai.projects.models.LiveDecisionInputImageParam] """ - 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"] + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Days of the month for the recurrence schedule. Required.""" + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionStoredInputItemParamType.FUNCTION_CALL_OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the function tool call output. Always ``function_call_output``. Required. + FUNCTION_CALL_OUTPUT.""" + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) + ) + """Required. Is either a str type or a [Union[\"_models.LiveDecisionInputTextParam\", + \"_models.LiveDecisionInputImageParam\"]] type.""" @overload def __init__( self, *, - days_of_month: list[int], + id: str, # pylint: disable=redefined-builtin + call_id: str, + output: Union[str, list[Union["_models.LiveDecisionInputTextParam", "_models.LiveDecisionInputImageParam"]]], + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, ) -> None: ... @overload @@ -15610,43 +16123,56 @@ 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 = LiveDecisionStoredInputItemParamType.FUNCTION_CALL_OUTPUT # type: ignore -class NamespaceToolParam( - Tool, discriminator="namespace" +class LiveDecisionStoredFunctionCallParam( + LiveDecisionStoredInputItemParam, discriminator="function_call" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Namespace. + """LiveDecisionStoredFunctionCallParam. - :ivar type: The type of the tool. Always ``namespace``. Required. NAMESPACE. - :vartype type: str or ~azure.ai.projects.models.NAMESPACE - :ivar name: The namespace name used in tool calls (for example, ``crm``). Required. + :ivar id: Required. + :vartype id: str + :ivar call_id: The unique ID of the function tool call generated by the model. Required. + :vartype call_id: str + :ivar status: Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.LiveFunctionCallItemStatus + :ivar type: The item type. Always ``function_call``. Required. FUNCTION_CALL. + :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL + :ivar name: Required. :vartype name: str - :ivar description: A description of the namespace shown to the model. Required. - :vartype description: str - :ivar tools: The function/custom tools available inside this namespace. Required. - :vartype tools: list[~azure.ai.projects.models.FunctionToolParam or - ~azure.ai.projects.models.CustomToolParam] + :ivar namespace: + :vartype namespace: str + :ivar arguments: The function arguments as a JSON string. Required. + :vartype arguments: str """ - type: Literal[ToolType.NAMESPACE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``namespace``. Required. NAMESPACE.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The namespace name used in tool calls (for example, ``crm``). Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A description of the namespace shown to the model. Required.""" - tools: list[Union["_models.FunctionToolParam", "_models.CustomToolParam"]] = rest_field( + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the function tool call generated by the model. Required.""" + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The function/custom tools available inside this namespace. Required.""" + """Known values are: \"in_progress\", \"completed\", and \"incomplete\".""" + type: Literal[LiveDecisionStoredInputItemParamType.FUNCTION_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The item type. Always ``function_call``. Required. FUNCTION_CALL.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + namespace: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The function arguments as a JSON string. Required.""" @overload def __init__( self, *, + id: str, # pylint: disable=redefined-builtin + call_id: str, name: str, - description: str, - tools: list[Union["_models.FunctionToolParam", "_models.CustomToolParam"]], + arguments: str, + status: Optional[Union[str, "_models.LiveFunctionCallItemStatus"]] = None, + namespace: Optional[str] = None, ) -> None: ... @overload @@ -15658,18 +16184,18 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.NAMESPACE # type: ignore + self.type = LiveDecisionStoredInputItemParamType.FUNCTION_CALL # type: ignore -class NoAuthenticationCredentials(BaseCredentials, discriminator="None"): - """Credentials that do not require authentication. +class LiveDecisionStoredInputItemParamMessage(LiveDecisionStoredInputItemParam, discriminator="message"): + """LiveDecisionStoredInputItemParamMessage. - :ivar type: The credential type. Required. No credential. - :vartype type: str or ~azure.ai.projects.models.NONE + :ivar type: Required. MESSAGE. + :vartype type: str or ~azure.ai.projects.models.MESSAGE """ - type: Literal[CredentialType.NONE] = rest_discriminator(name="type", visibility=["read"]) # type: ignore - """The credential type. Required. No credential.""" + type: Literal[LiveDecisionStoredInputItemParamType.MESSAGE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. MESSAGE.""" @overload def __init__( @@ -15685,35 +16211,41 @@ 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 + self.type = LiveDecisionStoredInputItemParamType.MESSAGE # type: ignore -class OneTimeTrigger(Trigger, discriminator="OneTime"): # pylint: disable=docstring-keyword-should-match-keyword-only - """One-time trigger. +class LiveDecisionTriggerInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveDecisionTriggerInputParam. - :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 + :ivar type: Required. Default value is "decisions". + :vartype type: str + :ivar event_type: Required. Is either a Literal["session.input_transcript.delta"] type or a + Literal["session.output_transcript.delta"] type. + :vartype event_type: str or str + :ivar decisions: Questions evaluated using the current transcript and the session's shared + Decision items. Required. + :vartype decisions: ~azure.ai.projects.models.LiveDecisionQuestionsInputParam """ - 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["decisions"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"decisions\".""" + event_type: Literal["session.input_transcript.delta", "session.output_transcript.delta"] = 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. Defaults to ``UTC``.""" + """Required. Is either a Literal[\"session.input_transcript.delta\"] type or a + Literal[\"session.output_transcript.delta\"] type.""" + decisions: "_models.LiveDecisionQuestionsInputParam" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Questions evaluated using the current transcript and the session's shared Decision items. + Required.""" @overload def __init__( self, *, - trigger_at: datetime.datetime, - time_zone: Optional[str] = None, + event_type: Literal["session.input_transcript.delta", "session.output_transcript.delta"], + decisions: "_models.LiveDecisionQuestionsInputParam", ) -> None: ... @overload @@ -15725,30 +16257,33 @@ 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: Literal["decisions"] = "decisions" -class OpenApiAuthDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """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 LiveDelegationReasoningInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reasoning options for Responses requests made on behalf of the Live session. - :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 effort: Known values are: "none", "minimal", "low", "medium", "high", and "xhigh". + :vartype effort: str or ~azure.ai.projects.models.LiveReasoningEffort + :ivar summary: Known values are: "concise", "detailed", and "auto". + :vartype summary: str or ~azure.ai.projects.models.LiveReasoningSummary """ - __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\".""" + effort: Optional[Union[str, "_models.LiveReasoningEffort"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"none\", \"minimal\", \"low\", \"medium\", \"high\", and \"xhigh\".""" + summary: Optional[Union[str, "_models.LiveReasoningSummary"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"concise\", \"detailed\", and \"auto\".""" @overload def __init__( self, *, - type: str, + effort: Optional[Union[str, "_models.LiveReasoningEffort"]] = None, + summary: Optional[Union[str, "_models.LiveReasoningSummary"]] = None, ) -> None: ... @overload @@ -15762,19 +16297,23 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiAnonymousAuthDetails(OpenApiAuthDetails, discriminator="anonymous"): - """Security details for OpenApi anonymous authentication. +class LiveDelegationTextInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Text generation options for the Live session’s Responses backend. - :ivar type: The object type, which is always 'anonymous'. Required. ANONYMOUS. - :vartype type: str or ~azure.ai.projects.models.ANONYMOUS + :ivar verbosity: Known values are: "low", "medium", and "high". + :vartype verbosity: str or ~azure.ai.projects.models.LiveTextVerbosity """ - 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.""" + verbosity: Optional[Union[str, "_models.LiveTextVerbosity"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"low\", \"medium\", and \"high\".""" @overload def __init__( self, + *, + verbosity: Optional[Union[str, "_models.LiveTextVerbosity"]] = None, ) -> None: ... @overload @@ -15786,50 +16325,42 @@ 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 -class OpenApiFunctionDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The input definition information for an openapi function. +class LiveFileSearchToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveFileSearchToolInputParam. - :ivar name: The name of the function to be called. Required. + :ivar type: Required. Default value is "file_search". + :vartype type: str + """ + + type: Literal["file_search"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"file_search\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["file_search"] = "file_search" + + +class LiveFunctionToolChoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveFunctionToolChoiceParam. + + :ivar type: The tool to call. Always ``function``. Required. Default value is "function". + :vartype type: str + :ivar name: The name of the function tool to call. 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] """ + type: Literal["function"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``function``. Required. Default value is \"function\".""" 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.""" + """The name of the function tool to call. Required.""" @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 @@ -15841,36 +16372,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["function"] = "function" -class OpenApiFunctionDefinitionFunction(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """OpenApiFunctionDefinitionFunction. +class LiveFunctionToolInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A function tool available to the Responses backend when the Live model delegates a task. - :ivar name: The name of the function to be called. Required. + :ivar type: The tool type. Always ``function``. Required. Default value is "function". + :vartype type: str + :ivar name: The name the delegated Responses model uses when calling this function. 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. + :ivar description: :vartype description: str - :ivar parameters: The parameters the functions accepts, described as a JSON Schema object. - Required. + :ivar parameters: :vartype parameters: dict[str, any] + :ivar strict: + :vartype strict: bool """ + type: Literal["function"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool type. Always ``function``. Required. Default value is \"function\".""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function to be called. Required.""" + """The name the delegated Responses model uses when calling this function. 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.""" + parameters: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + strict: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, name: str, - parameters: dict[str, Any], description: Optional[str] = None, + parameters: Optional[dict[str, Any]] = None, + strict: Optional[bool] = None, ) -> None: ... @overload @@ -15882,31 +16417,57 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["function"] = "function" -class OpenApiManagedAuthDetails( - OpenApiAuthDetails, discriminator="managed_identity" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Security details for OpenApi managed_identity authentication. - - :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 - """ +class LiveHostedShellContainerAutoParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveHostedShellContainerAutoParam. - 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( + :ivar type: Automatically creates a container for this request. Required. Default value is + "container_auto". + :vartype type: str + :ivar file_ids: + :vartype file_ids: list[str] + :ivar memory_limit: Known values are: "1g", "4g", "16g", and "64g". + :vartype memory_limit: str or ~azure.ai.projects.models.LiveContainerMemoryLimit + :ivar network_policy: Is either a LiveContainerNetworkPolicyDisabledParam type or a + LiveHostedShellNetworkPolicyAllowlistParam type. + :vartype network_policy: ~azure.ai.projects.models.LiveContainerNetworkPolicyDisabledParam or + ~azure.ai.projects.models.LiveHostedShellNetworkPolicyAllowlistParam + :ivar skills: + :vartype skills: list[~azure.ai.projects.models.LiveSkillReferenceParam or + ~azure.ai.projects.models.LiveInlineSkillParam] + """ + + type: Literal["container_auto"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Automatically creates a container for this request. Required. Default value is + \"container_auto\".""" + file_ids: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + memory_limit: Optional[Union[str, "_models.LiveContainerMemoryLimit"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"1g\", \"4g\", \"16g\", and \"64g\".""" + network_policy: Optional[ + Union["_models.LiveContainerNetworkPolicyDisabledParam", "_models.LiveHostedShellNetworkPolicyAllowlistParam"] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Is either a LiveContainerNetworkPolicyDisabledParam type or a + LiveHostedShellNetworkPolicyAllowlistParam type.""" + skills: Optional[list[Union["_models.LiveSkillReferenceParam", "_models.LiveInlineSkillParam"]]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Connection auth security details. Required.""" @overload def __init__( self, *, - security_scheme: "_models.OpenApiManagedSecurityScheme", + file_ids: Optional[list[str]] = None, + memory_limit: Optional[Union[str, "_models.LiveContainerMemoryLimit"]] = None, + network_policy: Optional[ + Union[ + "_models.LiveContainerNetworkPolicyDisabledParam", "_models.LiveHostedShellNetworkPolicyAllowlistParam" + ] + ] = None, + skills: Optional[list[Union["_models.LiveSkillReferenceParam", "_models.LiveInlineSkillParam"]]] = None, ) -> None: ... @overload @@ -15918,24 +16479,32 @@ 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 + self.type: Literal["container_auto"] = "container_auto" -class OpenApiManagedSecurityScheme(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Security scheme for OpenApi managed_identity authentication. +class LiveHostedShellNetworkPolicyAllowlistParam( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """LiveHostedShellNetworkPolicyAllowlistParam. - :ivar audience: Authentication scope for managed_identity auth type. Required. - :vartype audience: str + :ivar type: Allow outbound network access only to specified domains. Always ``allowlist``. + Required. Default value is "allowlist". + :vartype type: str + :ivar allowed_domains: A list of allowed domains when type is ``allowlist``. Required. + :vartype allowed_domains: list[str] """ - audience: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Authentication scope for managed_identity auth type. Required.""" + type: Literal["allowlist"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Allow outbound network access only to specified domains. Always ``allowlist``. Required. + Default value is \"allowlist\".""" + allowed_domains: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A list of allowed domains when type is ``allowlist``. Required.""" @overload def __init__( self, *, - audience: str, + allowed_domains: list[str], ) -> None: ... @overload @@ -15947,32 +16516,45 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["allowlist"] = "allowlist" -class OpenApiProjectConnectionAuthDetails( - OpenApiAuthDetails, discriminator="project_connection" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Security details for OpenApi project connection authentication. +class LiveHostedShellToolInputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Responses shell tool. Use a hosted container or return local shell results with + response.item.create. Domain secrets are not supported. - :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 type: Required. Default value is "shell". + :vartype type: str + :ivar environment: Is one of the following types: LiveHostedShellContainerAutoParam, + LiveContainerReferenceParam, LiveLocalEnvironmentParam + :vartype environment: ~azure.ai.projects.models.LiveHostedShellContainerAutoParam or + ~azure.ai.projects.models.LiveContainerReferenceParam or + ~azure.ai.projects.models.LiveLocalEnvironmentParam """ - 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"] - ) - """Project connection auth security details. Required.""" + type: Literal["shell"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"shell\".""" + environment: Optional[ + Union[ + "_models.LiveHostedShellContainerAutoParam", + "_models.LiveContainerReferenceParam", + "_models.LiveLocalEnvironmentParam", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Is one of the following types: LiveHostedShellContainerAutoParam, LiveContainerReferenceParam, + LiveLocalEnvironmentParam""" @overload def __init__( self, *, - security_scheme: "_models.OpenApiProjectConnectionSecurityScheme", + environment: Optional[ + Union[ + "_models.LiveHostedShellContainerAutoParam", + "_models.LiveContainerReferenceParam", + "_models.LiveLocalEnvironmentParam", + ] + ] = None, ) -> None: ... @overload @@ -15984,24 +16566,45 @@ 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 + self.type: Literal["shell"] = "shell" -class OpenApiProjectConnectionSecurityScheme(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Security scheme for OpenApi managed_identity authentication. +class LiveImageGenerationToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveImageGenerationToolInputParam. - :ivar project_connection_id: Project connection id for Project Connection auth type. Required. - :vartype project_connection_id: str + :ivar type: Required. Default value is "image_generation". + :vartype type: str """ - project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Project connection id for Project Connection auth type. Required.""" + type: Literal["image_generation"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"image_generation\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["image_generation"] = "image_generation" + + +class LiveInitialItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A developer, user, or assistant message supplied as text history before the Live session + starts. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveInitialAssistantMessageItemParam, LiveInitialDeveloperMessageItemParam, + LiveInitialUserMessageItemParam + + :ivar role: Required. Known values are: "developer", "user", and "assistant". + :vartype role: str or ~azure.ai.projects.models.LiveInitialItemType + """ + + __mapping__: dict[str, _Model] = {} + role: str = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"developer\", \"user\", and \"assistant\".""" @overload def __init__( self, *, - project_connection_id: str, + role: str, ) -> None: ... @overload @@ -16015,35 +16618,50 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OpenApiTool(Tool, discriminator="openapi"): # pylint: disable=docstring-keyword-should-match-keyword-only - """The input definition information for an OpenAPI tool as used to configure an agent. +class LiveInitialAssistantMessageItemParam( + LiveInitialItem, discriminator="assistant" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An assistant message included in the initial text history of a Live session. - :ivar type: The object type, which is always 'openapi'. Required. OPENAPI. - :vartype type: str or ~azure.ai.projects.models.OPENAPI - :ivar tool_configs: Deprecated. This property is deprecated and will be removed in a future - version. - :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] - :ivar openapi: The openapi function definition. Required. - :vartype openapi: ~azure.ai.projects.models.OpenApiFunctionDefinition + :ivar id: + :vartype id: str + :ivar type: The history item type. Always ``message``. Default value is "message". + :vartype type: str + :ivar status: Known values are: "incomplete" and "completed". + :vartype status: str or ~azure.ai.projects.models.LiveInitialMessageStatus + :ivar role: The author of this history message. Always ``assistant``. Required. ASSISTANT. + :vartype role: str or ~azure.ai.projects.models.ASSISTANT + :ivar content: The message content. Supply exactly one text part for the initial Live + conversation history. Required. + :vartype content: list[~azure.ai.projects.models.LiveInitialTextContentPartParam or + ~azure.ai.projects.models.LiveInitialOutputTextContentPartParam] """ - 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.""" - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Optional[Literal["message"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The history item type. Always ``message``. Default value is \"message\".""" + status: Optional[Union[str, "_models.LiveInitialMessageStatus"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Deprecated. This property is deprecated and will be removed in a future version.""" - openapi: "_models.OpenApiFunctionDefinition" = rest_field( - visibility=["read", "create", "update", "delete", "query"] + """Known values are: \"incomplete\" and \"completed\".""" + role: Literal[LiveInitialItemType.ASSISTANT] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The author of this history message. Always ``assistant``. Required. ASSISTANT.""" + content: list[Union["_models.LiveInitialTextContentPartParam", "_models.LiveInitialOutputTextContentPartParam"]] = ( + rest_field(visibility=["read", "create", "update", "delete", "query"]) ) - """The openapi function definition. Required.""" + """The message content. Supply exactly one text part for the initial Live conversation history. + Required.""" @overload def __init__( self, *, - openapi: "_models.OpenApiFunctionDefinition", - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + content: list[ + Union["_models.LiveInitialTextContentPartParam", "_models.LiveInitialOutputTextContentPartParam"] + ], + id: Optional[str] = None, # pylint: disable=redefined-builtin + type: Optional[Literal["message"]] = None, + status: Optional[Union[str, "_models.LiveInitialMessageStatus"]] = None, ) -> None: ... @overload @@ -16055,43 +16673,50 @@ 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 + self.role = LiveInitialItemType.ASSISTANT # type: ignore -class OpenApiToolboxTool( - ToolboxTool, discriminator="openapi" +class LiveInitialDeveloperMessageItemParam( + LiveInitialItem, discriminator="developer" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """An OpenAPI tool stored in a toolbox. + """A developer message included in the initial text history of a Live session. - :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 type: 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 id: + :vartype id: str + :ivar type: The history item type. Always ``message``. Default value is "message". + :vartype type: str + :ivar status: Known values are: "incomplete" and "completed". + :vartype status: str or ~azure.ai.projects.models.LiveInitialMessageStatus + :ivar role: The author of this history message. Always ``developer``. Required. DEVELOPER. + :vartype role: str or ~azure.ai.projects.models.DEVELOPER + :ivar content: The message content. Supply exactly one text part for the initial Live + conversation history. Required. + :vartype content: list[~azure.ai.projects.models.LiveInitialInputTextContentPartParam] """ - type: Literal[ToolboxToolType.OPENAPI] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. OPENAPI.""" - openapi: "_models.OpenApiFunctionDefinition" = rest_field( + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Optional[Literal["message"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The history item type. Always ``message``. Default value is \"message\".""" + status: Optional[Union[str, "_models.LiveInitialMessageStatus"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The openapi function definition. Required.""" + """Known values are: \"incomplete\" and \"completed\".""" + role: Literal[LiveInitialItemType.DEVELOPER] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The author of this history message. Always ``developer``. Required. DEVELOPER.""" + content: list["_models.LiveInitialInputTextContentPartParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The message content. Supply exactly one text part for the initial Live conversation history. + Required.""" @overload def __init__( self, *, - openapi: "_models.OpenApiFunctionDefinition", - name: Optional[str] = None, - description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + content: list["_models.LiveInitialInputTextContentPartParam"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + type: Optional[Literal["message"]] = None, + status: Optional[Union[str, "_models.LiveInitialMessageStatus"]] = None, ) -> None: ... @overload @@ -16103,28 +16728,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolboxToolType.OPENAPI # type: ignore + self.role = LiveInitialItemType.DEVELOPER # type: ignore -class OptimizationContext(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Base model for typed optimization context. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - SteeringPromptOptimizationContext +class LiveInitialInputTextContentPartParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Text supplied in a developer or user message when starting a Live session. - :ivar type: Optimization context type discriminator. Required. "steering_prompt" - :vartype type: str or ~azure.ai.projects.models.OptimizationContextType + :ivar type: The text content type. Always ``input_text``. Default value is "input_text". + :vartype type: str + :ivar text: The message text to include in the Live session’s initial conversation history. + Required. + :vartype text: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Optimization context type discriminator. Required. \"steering_prompt\"""" + type: Optional[Literal["input_text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text content type. Always ``input_text``. Default value is \"input_text\".""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The message text to include in the Live session’s initial conversation history. Required.""" @overload def __init__( self, *, - type: str, + text: str, + type: Optional[Literal["input_text"]] = None, ) -> None: ... @overload @@ -16138,40 +16765,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TelemetryEndpoint(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A telemetry export endpoint configuration. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - OtlpTelemetryEndpoint +class LiveInitialOutputTextContentPartParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Assistant output text supplied as conversation history when starting a Live session. - :ivar kind: The telemetry export endpoint kind. Required. "OTLP" - :vartype kind: str or ~azure.ai.projects.models.TelemetryEndpointKind - :ivar data: Data types to export to this endpoint. Use an empty array to export no data. + :ivar type: The text content type. Always ``output_text``. Required. Default value is + "output_text". + :vartype type: str + :ivar text: The message text to include in the Live session’s initial conversation history. Required. - :vartype data: list[str or ~azure.ai.projects.models.TelemetryDataKind] - :ivar auth: Optional authentication configuration. - :vartype auth: ~azure.ai.projects.models.TelemetryEndpointAuth + :vartype text: str """ - __mapping__: dict[str, _Model] = {} - kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) - """The telemetry export endpoint kind. Required. \"OTLP\"""" - data: list[Union[str, "_models.TelemetryDataKind"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Data types to export to this endpoint. Use an empty array to export no data. Required.""" - auth: Optional["_models.TelemetryEndpointAuth"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional authentication configuration.""" + type: Literal["output_text"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text content type. Always ``output_text``. Required. Default value is \"output_text\".""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The message text to include in the Live session’s initial conversation history. Required.""" @overload def __init__( self, *, - kind: str, - data: list[Union[str, "_models.TelemetryDataKind"]], - auth: Optional["_models.TelemetryEndpointAuth"] = None, + text: str, ) -> None: ... @overload @@ -16183,47 +16797,116 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["output_text"] = "output_text" -class OtlpTelemetryEndpoint( - TelemetryEndpoint, discriminator="OTLP" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """An OTLP (OpenTelemetry Protocol) telemetry export endpoint. +class LiveInitialSessionAudioOutputParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Settings for speech generated by the Live model. Choose the voice before starting the session. - :ivar data: Data types to export to this endpoint. Use an empty array to export no data. - Required. - :vartype data: list[str or ~azure.ai.projects.models.TelemetryDataKind] - :ivar auth: Optional authentication configuration. - :vartype auth: ~azure.ai.projects.models.TelemetryEndpointAuth - :ivar kind: The endpoint kind, always 'OTLP' for OpenTelemetry Protocol endpoints. Required. - OpenTelemetry Protocol (OTLP) endpoint. - :vartype kind: str or ~azure.ai.projects.models.OTLP - :ivar endpoint: The OTLP collector endpoint URL. Required. - :vartype endpoint: str - :ivar protocol: The transport protocol for the OTLP endpoint. Required. Known values are: - "Http" and "Grpc". - :vartype protocol: str or ~azure.ai.projects.models.TelemetryTransportProtocol + :ivar voice: The voice used for Live speech, as a built-in voice name or a custom voice object + containing its ID. Defaults to ``marin`` and cannot change after startup. Is one of the + following types: str, Literal["alloy"], Literal["ash"], Literal["ballad"], Literal["beacon"], + Literal["bossa"], Literal["brise"], Literal["cedar"], Literal["cinder"], Literal["coral"], + Literal["delta"], Literal["echo"], Literal["flitz"], Literal["gleam"], Literal["harema"], + Literal["juni"], Literal["marin"], Literal["meridian"], Literal["nira"], Literal["noeul"], + Literal["nuri"], Literal["quartz"], Literal["ripple"], Literal["sage"], Literal["shida"], + Literal["shimmer"], Literal["sillage"], Literal["stone"], Literal["tempo"], Literal["verse"], + Literal["vesper"], Literal["willow"], LiveCustomVoiceParam + :vartype voice: str or str or str or str or str or str or str or str or str or str or str or + str or str or str or str or str or str or str or str or str or str or str or str or str or str + or str or str or str or str or str or str or str or + ~azure.ai.projects.models.LiveCustomVoiceParam """ - kind: Literal[TelemetryEndpointKind.OTLP] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The endpoint kind, always 'OTLP' for OpenTelemetry Protocol endpoints. Required. OpenTelemetry - Protocol (OTLP) endpoint.""" - endpoint: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The OTLP collector endpoint URL. Required.""" - protocol: Union[str, "_models.TelemetryTransportProtocol"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The transport protocol for the OTLP endpoint. Required. Known values are: \"Http\" and - \"Grpc\".""" + voice: Optional[ + Union[ + str, + Literal["alloy"], + Literal["ash"], + Literal["ballad"], + Literal["beacon"], + Literal["bossa"], + Literal["brise"], + Literal["cedar"], + Literal["cinder"], + Literal["coral"], + Literal["delta"], + Literal["echo"], + Literal["flitz"], + Literal["gleam"], + Literal["harema"], + Literal["juni"], + Literal["marin"], + Literal["meridian"], + Literal["nira"], + Literal["noeul"], + Literal["nuri"], + Literal["quartz"], + Literal["ripple"], + Literal["sage"], + Literal["shida"], + Literal["shimmer"], + Literal["sillage"], + Literal["stone"], + Literal["tempo"], + Literal["verse"], + Literal["vesper"], + Literal["willow"], + "_models.LiveCustomVoiceParam", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice used for Live speech, as a built-in voice name or a custom voice object containing + its ID. Defaults to ``marin`` and cannot change after startup. Is one of the following types: + str, Literal[\"alloy\"], Literal[\"ash\"], Literal[\"ballad\"], Literal[\"beacon\"], + Literal[\"bossa\"], Literal[\"brise\"], Literal[\"cedar\"], Literal[\"cinder\"], + Literal[\"coral\"], Literal[\"delta\"], Literal[\"echo\"], Literal[\"flitz\"], + Literal[\"gleam\"], Literal[\"harema\"], Literal[\"juni\"], Literal[\"marin\"], + Literal[\"meridian\"], Literal[\"nira\"], Literal[\"noeul\"], Literal[\"nuri\"], + Literal[\"quartz\"], Literal[\"ripple\"], Literal[\"sage\"], Literal[\"shida\"], + Literal[\"shimmer\"], Literal[\"sillage\"], Literal[\"stone\"], Literal[\"tempo\"], + Literal[\"verse\"], Literal[\"vesper\"], Literal[\"willow\"], LiveCustomVoiceParam""" @overload def __init__( self, *, - data: list[Union[str, "_models.TelemetryDataKind"]], - endpoint: str, - protocol: Union[str, "_models.TelemetryTransportProtocol"], - auth: Optional["_models.TelemetryEndpointAuth"] = None, + voice: Optional[ + Union[ + str, + Literal["alloy"], + Literal["ash"], + Literal["ballad"], + Literal["beacon"], + Literal["bossa"], + Literal["brise"], + Literal["cedar"], + Literal["cinder"], + Literal["coral"], + Literal["delta"], + Literal["echo"], + Literal["flitz"], + Literal["gleam"], + Literal["harema"], + Literal["juni"], + Literal["marin"], + Literal["meridian"], + Literal["nira"], + Literal["noeul"], + Literal["nuri"], + Literal["quartz"], + Literal["ripple"], + Literal["sage"], + Literal["shida"], + Literal["shimmer"], + Literal["sillage"], + Literal["stone"], + Literal["tempo"], + Literal["verse"], + Literal["vesper"], + Literal["willow"], + "_models.LiveCustomVoiceParam", + ] + ] = None, ) -> None: ... @overload @@ -16235,43 +16918,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = TelemetryEndpointKind.OTLP # type: ignore -class PendingUploadRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Represents a request for a pending upload. +class LiveInitialSessionAudioParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Startup audio configuration. Only primary WebSockets accept audio.format; WebRTC and SIP + negotiate their media format. Voice and format are immutable after startup. - :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. 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 + :ivar format: Audio encoding and sample rate for audio sent and received over a Live WebSocket + connection. WebRTC and SIP negotiate their media format separately. + :vartype format: ~azure.ai.projects.models.LiveAudioFormat + :ivar output: The voice used for speech generated by the Live model. + :vartype output: ~azure.ai.projects.models.LiveInitialSessionAudioOutputParam """ - 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.BLOB_REFERENCE] = rest_field( - name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + format: Optional["_models.LiveAudioFormat"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Audio encoding and sample rate for audio sent and received over a Live WebSocket connection. + WebRTC and SIP negotiate their media format separately.""" + output: Optional["_models.LiveInitialSessionAudioOutputParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The type of pending upload. Required. Deprecated: the service never read this value and - silently ignored it. Use TemporaryBlobReference instead.""" + """The voice used for speech generated by the Live model.""" @overload def __init__( self, *, - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], - pending_upload_id: Optional[str] = None, - connection_name: Optional[str] = None, + format: Optional["_models.LiveAudioFormat"] = None, + output: Optional["_models.LiveInitialSessionAudioOutputParam"] = None, ) -> None: ... @overload @@ -16285,45 +16958,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PendingUploadResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Represents the response for a pending upload request. +class LiveInitialTextContentPartParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Assistant text supplied as conversation history when starting a Live session. - :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. 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 + :ivar type: The text content type. Always ``text``. Default value is "text". + :vartype type: str + :ivar text: The message text to include in the Live session’s initial conversation history. + Required. + :vartype text: str """ - blob_reference: "_models.BlobReference" = rest_field( - name="blobReference", visibility=["read", "create", "update", "delete", "query"] - ) - """Container-level read, write, list SAS. Required.""" - pending_upload_id: str = rest_field( - name="pendingUploadId", visibility=["read", "create", "update", "delete", "query"] - ) - """ID for this upload request. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Version of asset to be created if user did not specify version when initially creating upload.""" - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] = rest_field( - name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] - ) - """The type of pending upload. Required. Deprecated: the service never read this value and - silently ignored it. Use TemporaryBlobReference instead.""" + type: Optional[Literal["text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text content type. Always ``text``. Default value is \"text\".""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The message text to include in the Live session’s initial conversation history. Required.""" @overload def __init__( self, *, - blob_reference: "_models.BlobReference", - pending_upload_id: str, - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], - version: Optional[str] = None, + text: str, + type: Optional[Literal["text"]] = None, ) -> None: ... @overload @@ -16337,23 +16992,47 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PickPropertiesVoiceAgentAudioConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The template for picking properties. +class LiveInitialUserMessageItemParam( + LiveInitialItem, discriminator="user" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A user message included in the initial text history of a Live session. - :ivar output: Output (agent speech) audio configuration. - :vartype output: ~azure.ai.projects.models.VoiceAgentAudioOutputConfig + :ivar id: + :vartype id: str + :ivar type: The history item type. Always ``message``. Default value is "message". + :vartype type: str + :ivar status: Known values are: "incomplete" and "completed". + :vartype status: str or ~azure.ai.projects.models.LiveInitialMessageStatus + :ivar role: The author of this history message. Always ``user``. Required. USER. + :vartype role: str or ~azure.ai.projects.models.USER + :ivar content: The message content. Supply exactly one text part for the initial Live + conversation history. Required. + :vartype content: list[~azure.ai.projects.models.LiveInitialInputTextContentPartParam] """ - output: Optional["_models.VoiceAgentAudioOutputConfig"] = rest_field( + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Optional[Literal["message"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The history item type. Always ``message``. Default value is \"message\".""" + status: Optional[Union[str, "_models.LiveInitialMessageStatus"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Output (agent speech) audio configuration.""" + """Known values are: \"incomplete\" and \"completed\".""" + role: Literal[LiveInitialItemType.USER] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The author of this history message. Always ``user``. Required. USER.""" + content: list["_models.LiveInitialInputTextContentPartParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The message content. Supply exactly one text part for the initial Live conversation history. + Required.""" @overload def __init__( self, *, - output: Optional["_models.VoiceAgentAudioOutputConfig"] = None, + content: list["_models.LiveInitialInputTextContentPartParam"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + type: Optional[Literal["message"]] = None, + status: Optional[Union[str, "_models.LiveInitialMessageStatus"]] = None, ) -> None: ... @overload @@ -16365,38 +17044,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.role = LiveInitialItemType.USER # type: ignore -class ProceduralMemoryItem( - MemoryItem, discriminator="procedural" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A memory item containing a procedure extracted from conversations. +class LiveInlineSkillParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveInlineSkillParam. - :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 + :ivar type: Defines an inline skill for this request. Required. Default value is "inline". + :vartype type: str + :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.LiveInlineSkillSourceParam """ - 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.""" + type: Literal["inline"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Defines an inline skill for this request. Required. Default value is \"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.LiveInlineSkillSourceParam" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Inline skill payload. Required.""" @overload def __init__( self, *, - memory_id: str, - updated_at: datetime.datetime, - scope: str, - content: str, + name: str, + description: str, + source: "_models.LiveInlineSkillSourceParam", ) -> None: ... @overload @@ -16408,24 +17089,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = MemoryItemKind.PROCEDURAL # type: ignore + self.type: Literal["inline"] = "inline" -class ProgrammaticToolCallingParam(Tool, discriminator="programmatic_tool_calling"): - """ProgrammaticToolCallingParam. +class LiveInlineSkillSourceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Inline skill payload. - :ivar type: The type of the tool. Always ``programmatic_tool_calling``. Required. - PROGRAMMATIC_TOOL_CALLING. - :vartype type: str or ~azure.ai.projects.models.PROGRAMMATIC_TOOL_CALLING + :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[ToolType.PROGRAMMATIC_TOOL_CALLING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``programmatic_tool_calling``. Required. - PROGRAMMATIC_TOOL_CALLING.""" + 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 @@ -16437,113 +17129,59 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.PROGRAMMATIC_TOOL_CALLING # type: ignore + self.type: Literal["base64"] = "base64" + self.media_type: Literal["application/zip"] = "application/zip" -class PromptAgentDefinition( - AgentDefinition, discriminator="prompt" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """The prompt agent definition. +class LiveServerEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An event sent by the Live API on a primary WebSocket or sideband connection. - :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. - :vartype rai_config: ~azure.ai.projects.models.RaiConfig - :ivar kind: Required. PROMPT. - :vartype kind: str or ~azure.ai.projects.models.PROMPT - :ivar harness: The managed runtime and agent loop used to execute this prompt agent. - :vartype harness: ~azure.ai.projects.models.AgentHarness - :ivar model: The model deployment to use for this agent. Required. - :vartype model: str - :ivar instructions: A system (or developer) message inserted into the model's context. - :vartype instructions: str - :ivar skills: The Foundry skills available to this prompt agent. An omitted skill version is - resolved and pinned when the agent version is created. - :vartype skills: list[~azure.ai.projects.models.SkillReference] - :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. 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. Defaults to ``1``. - :vartype top_p: float - :ivar reasoning: - :vartype reasoning: ~azure.ai.projects.models.Reasoning - :ivar tools: An array of tools the 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 tool_choice: How the model should select which tool (or tools) to use when generating a - response. See the ``tools`` parameter to see how to specify which tools the model can call. Is - either a str type or a ToolChoiceParam type. - :vartype tool_choice: str or ~azure.ai.projects.models.ToolChoiceParam - :ivar text: Configuration options for a text response from the model. Can be plain text or - structured JSON data. - :vartype text: ~azure.ai.projects.models.PromptAgentDefinitionTextOptions - :ivar structured_inputs: Set of structured inputs that can participate in prompt template - substitution or tool argument bindings. - :vartype structured_inputs: dict[str, ~azure.ai.projects.models.StructuredInputDefinition] + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveServerEventLiveDecisionEvent, LiveServerEventLiveDecisionItemCreated, + LiveServerEventLiveDecisionItemDeleted, LiveServerEventLiveErrorEvent, + LiveServerEventLiveInfoEvent, LiveServerEventLiveResponseEvent, + LiveServerEventLiveSessionClosed, LiveServerEventLiveCommentaryAppended, + LiveServerEventLiveDelegationCreated, LiveInputAudioAppend, LiveServerEventLiveInputAudioMuted, + LiveServerEventLiveInputAudioUnmuted, LiveServerEventLiveInputTranscriptDelta, + LiveServerEventLiveInstructionsAppended, LiveOutputAudioDelta, + LiveServerEventLiveOutputAudioFixturePlayed, LiveServerEventLiveOutputAudioFixturePlaying, + LiveServerEventLiveOutputTranscriptDelta, LiveServerEventLiveSessionStarted, + LiveServerEventLiveThinkingAppended, LiveServerEventLiveSessionUpdated, + LiveServerEventLiveSessionUsageUpdated, LiveServerEventLiveTransportAnswered, + LiveServerEventLiveTransportDtmfReceived, LiveServerEventLiveTransportDtmfSent, + LiveServerEventLiveTransportFailed, LiveServerEventLiveTransportRinging + + :ivar type: Required. Known values are: "session.started", "session.updated", + "session.input_audio.muted", "session.input_audio.unmuted", + "session.output_audio.fixture.playing", "session.output_audio.fixture.played", + "session.instructions.appended", "session.thinking.appended", "session.commentary.appended", + "session.input_audio.append", "session.output_audio.delta", "session.input_transcript.delta", + "session.output_transcript.delta", "session.delegation.created", "decision.event", + "decision.item.created", "decision.item.deleted", "response.event", "session.usage.updated", + "session.closed", "error", "info", "transport.dtmf.received", "transport.dtmf.sent", + "transport.ringing", "transport.answered", and "transport.failed". + :vartype type: str or ~azure.ai.projects.models.LiveServerEventType """ - kind: Literal[AgentKind.PROMPT] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. PROMPT.""" - harness: Optional["_models.AgentHarness"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The managed runtime and agent loop used to execute this prompt agent.""" - model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The model deployment to use for this agent. Required.""" - instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A system (or developer) message inserted into the model's context.""" - skills: Optional[list["_models.SkillReference"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The Foundry skills available to this prompt agent. An omitted skill version is resolved and - pinned when the agent version is created.""" - 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. 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. 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 - use by setting the ``tool_choice`` parameter.""" - tool_choice: Optional[Union[str, "_models.ToolChoiceParam"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """How the model should select which tool (or tools) to use when generating a response. See the - ``tools`` parameter to see how to specify which tools the model can call. Is either a str type - or a ToolChoiceParam type.""" - text: Optional["_models.PromptAgentDefinitionTextOptions"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration options for a text response from the model. Can be plain text or structured JSON - data.""" - structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Set of structured inputs that can participate in prompt template substitution or tool argument - bindings.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"session.started\", \"session.updated\", + \"session.input_audio.muted\", \"session.input_audio.unmuted\", + \"session.output_audio.fixture.playing\", \"session.output_audio.fixture.played\", + \"session.instructions.appended\", \"session.thinking.appended\", + \"session.commentary.appended\", \"session.input_audio.append\", + \"session.output_audio.delta\", \"session.input_transcript.delta\", + \"session.output_transcript.delta\", \"session.delegation.created\", \"decision.event\", + \"decision.item.created\", \"decision.item.deleted\", \"response.event\", + \"session.usage.updated\", \"session.closed\", \"error\", \"info\", + \"transport.dtmf.received\", \"transport.dtmf.sent\", \"transport.ringing\", + \"transport.answered\", and \"transport.failed\".""" @overload def __init__( self, *, - model: str, - rai_config: Optional["_models.RaiConfig"] = None, - harness: Optional["_models.AgentHarness"] = None, - instructions: Optional[str] = None, - skills: Optional[list["_models.SkillReference"]] = None, - temperature: Optional[float] = None, - top_p: Optional[float] = None, - reasoning: Optional["_models.Reasoning"] = None, - tools: Optional[list["_models.Tool"]] = None, - tool_choice: Optional[Union[str, "_models.ToolChoiceParam"]] = None, - text: Optional["_models.PromptAgentDefinitionTextOptions"] = None, - structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = None, + type: str, ) -> None: ... @overload @@ -16555,26 +17193,35 @@ 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 - -class PromptAgentDefinitionTextOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """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 +class LiveInputAudioAppend( + LiveServerEvent, discriminator="session.input_audio.append" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Input audio received from the primary transport and reflected to a Live sideband connection + before model-input muting. + + :ivar type: The event type, always ``session.input_audio.append``. Required. + SESSION_INPUT_AUDIO_APPEND. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_AUDIO_APPEND + :ivar audio: Base64-encoded raw mono PCM16LE at 24 kHz received from the primary transport, + reflected to the sideband before model-input muting. This server event uses the same audio key + as the client command, but is not an acknowledgment of it. Required. + :vartype audio: str """ - format: Optional["_models.TextResponseFormat"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) + type: Literal[LiveServerEventType.SESSION_INPUT_AUDIO_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.input_audio.append``. Required. SESSION_INPUT_AUDIO_APPEND.""" + audio: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64-encoded raw mono PCM16LE at 24 kHz received from the primary transport, reflected to the + sideband before model-input muting. This server event uses the same audio key as the client + command, but is not an acknowledgment of it. Required.""" @overload def __init__( self, *, - format: Optional["_models.TextResponseFormat"] = None, + audio: str, ) -> None: ... @overload @@ -16586,40 +17233,48 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.SESSION_INPUT_AUDIO_APPEND # type: ignore -class PromptBasedEvaluatorDefinition( - EvaluatorDefinition, discriminator="prompt" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Prompt-based evaluator. +class LiveLiveError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Details of an error encountered by the Live session, including the affected parameter or client + command when available. - :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 + :ivar type: The category of error, such as ``invalid_request_error`` for an invalid Live client + command. Required. + :vartype type: str + :ivar code: A machine-readable code identifying the Live error, such as ``unknown_parameter``. + Required. + :vartype code: str + :ivar message: A human-readable explanation of the Live error. Required. + :vartype message: str + :ivar param: The parameter that caused the error, when applicable, such as ``session.voice``. + :vartype param: str + :ivar client_event_id: The event_id of the client command that caused the error, when supplied. + :vartype client_event_id: 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.""" + type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The category of error, such as ``invalid_request_error`` for an invalid Live client command. + Required.""" + code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A machine-readable code identifying the Live error, such as ``unknown_parameter``. Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable explanation of the Live error. Required.""" + param: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The parameter that caused the error, when applicable, such as ``session.voice``.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command that caused the error, when supplied.""" @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, + type: str, + code: str, + message: str, + param: Optional[str] = None, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -16631,38 +17286,28 @@ 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 -class PromptDataGenerationJobSource( - DataGenerationJobSource, discriminator="prompt" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Prompt source for data generation jobs — inline text provided by the user. +class LiveLocalEnvironmentParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveLocalEnvironmentParam. - :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 + :ivar type: Use a local computer environment. Required. Default value is "local". + :vartype type: str + :ivar skills: + :vartype skills: list[~azure.ai.projects.models.LiveLocalSkillParam] """ - 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.""" + type: Literal["local"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Use a local computer environment. Required. Default value is \"local\".""" + skills: Optional[list["_models.LiveLocalSkillParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) @overload def __init__( self, *, - prompt: str, - description: Optional[str] = None, + skills: Optional[list["_models.LiveLocalSkillParam"]] = None, ) -> None: ... @overload @@ -16674,41 +17319,34 @@ 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 + self.type: Literal["local"] = "local" -class PromptEvaluatorGenerationJobSource( - EvaluatorGenerationJobSource, discriminator="prompt" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Prompt source for evaluator generation jobs — inline text provided by the user. +class LiveLocalSkillParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveLocalSkillParam. - :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'). + :ivar name: The name of the skill. Required. + :vartype name: str + :ivar description: The description of the skill. Required. :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 + :ivar path: The path to the directory containing the skill. Required. + :vartype path: str """ - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of what this source represents — helps the pipeline interpret its content - (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" - type: Literal[EvaluatorGenerationJobSourceType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Prompt. Required. Prompt source — inline text - provided by the user.""" - prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Inline prompt text (e.g., agent description, policy text, supplementary context). Required.""" + 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, *, - prompt: str, - description: Optional[str] = None, + name: str, + description: str, + path: str, ) -> None: ... @overload @@ -16720,32 +17358,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorGenerationJobSourceType.PROMPT # type: ignore -class PromptOptimizationConfiguration( - AgentOptimizationConfigurationBase, discriminator="prompt_optimization" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Configuration for a one-shot prompt transformation without comparative evaluation. +class LiveMCPToolChoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveMCPToolChoiceParam. - :ivar type: Optimization type discriminator. Required. One-shot prompt optimization. - :vartype type: str or ~azure.ai.projects.models.PROMPT_OPTIMIZATION - :ivar context: Context used to steer prompt optimization. Omitted when no context is supplied. - :vartype context: list[~azure.ai.projects.models.OptimizationContext] + :ivar type: The tool to call. Always ``mcp``. Required. Default value is "mcp". + :vartype type: str + :ivar server_label: The label of the MCP server to call. Required. + :vartype server_label: str + :ivar name: + :vartype name: str """ - type: Literal[AgentOptimizationConfigurationType.PROMPT_OPTIMIZATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Optimization type discriminator. Required. One-shot prompt optimization.""" - context: Optional[list["_models.OptimizationContext"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Context used to steer prompt optimization. Omitted when no context is supplied.""" + type: Literal["mcp"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``mcp``. Required. Default value is \"mcp\".""" + server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The label of the MCP server to call. Required.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - context: Optional[list["_models.OptimizationContext"]] = None, + server_label: str, + name: Optional[str] = None, ) -> None: ... @overload @@ -16757,98 +17394,80 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = AgentOptimizationConfigurationType.PROMPT_OPTIMIZATION # type: ignore + self.type: Literal["mcp"] = "mcp" -class ProtocolConfiguration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Per-protocol configuration for the agent endpoint. +class LiveMCPToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveMCPToolInputParam. - :ivar activity: Configuration for the activity protocol. - :vartype activity: ~azure.ai.projects.models.ActivityProtocolConfiguration - :ivar responses: Configuration for the responses protocol. - :vartype responses: ~azure.ai.projects.models.ResponsesProtocolConfiguration - :ivar a2a: Configuration for the A2A protocol. - :vartype a2a: ~azure.ai.projects.models.A2AProtocolConfiguration - :ivar mcp: Configuration for the MCP protocol. - :vartype mcp: ~azure.ai.projects.models.McpProtocolConfiguration - :ivar invocations: Configuration for the invocations protocol. - :vartype invocations: ~azure.ai.projects.models.InvocationsProtocolConfiguration - :ivar invocations_ws: Configuration for the WebSocket-based invocations protocol. - :vartype invocations_ws: ~azure.ai.projects.models.InvocationsWsProtocolConfiguration + :ivar type: Required. Default value is "mcp". + :vartype type: str """ - activity: Optional["_models.ActivityProtocolConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for the activity protocol.""" - responses: Optional["_models.ResponsesProtocolConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for the responses protocol.""" - a2a: Optional["_models.A2AProtocolConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for the A2A protocol.""" - mcp: Optional["_models.McpProtocolConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for the MCP protocol.""" - invocations: Optional["_models.InvocationsProtocolConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for the invocations protocol.""" - invocations_ws: Optional["_models.InvocationsWsProtocolConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for the WebSocket-based invocations protocol.""" - - @overload - def __init__( - self, - *, - activity: Optional["_models.ActivityProtocolConfiguration"] = None, - responses: Optional["_models.ResponsesProtocolConfiguration"] = None, - a2a: Optional["_models.A2AProtocolConfiguration"] = None, - mcp: Optional["_models.McpProtocolConfiguration"] = None, - invocations: Optional["_models.InvocationsProtocolConfiguration"] = None, - invocations_ws: Optional["_models.InvocationsWsProtocolConfiguration"] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ + type: Literal["mcp"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"mcp\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["mcp"] = "mcp" -class ProtocolVersionRecord(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A record mapping for a single protocol and its version. +class LiveNamespaceToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveNamespaceToolInputParam. - :ivar protocol: The protocol type. Required. Known values are: "activity", "responses", "a2a", - "mcp", "invocations", "voice", "invocations_ws", and "voice_conversation_engine". - :vartype protocol: str or ~azure.ai.projects.models.AgentEndpointProtocol - :ivar version: The version string for the protocol, e.g. 'v0.1.1'. Required. - :vartype version: str + :ivar type: Required. Default value is "namespace". + :vartype type: str """ - protocol: Union[str, "_models.AgentEndpointProtocol"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The protocol type. Required. Known values are: \"activity\", \"responses\", \"a2a\", \"mcp\", - \"invocations\", \"voice\", \"invocations_ws\", and \"voice_conversation_engine\".""" - version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version string for the protocol, e.g. 'v0.1.1'. Required.""" + type: Literal["namespace"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"namespace\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["namespace"] = "namespace" + + +class LiveOutputAudioDelta( + LiveServerEvent, discriminator="session.output_audio.delta" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An audio chunk generated by the Live model. Decode and play primary WebSocket chunks in + delivery order using the configured session audio format. Sideband connections receive + reflected output audio with timestamps. + + :ivar type: The event type, always ``session.output_audio.delta``. Required. + SESSION_OUTPUT_AUDIO_DELTA. + :vartype type: str or ~azure.ai.projects.models.SESSION_OUTPUT_AUDIO_DELTA + :ivar delta: Base64-encoded raw audio. Primary WebSocket events use the session's configured + format; reflected sideband events use mono PCM16LE at 24 kHz. Required. + :vartype delta: str + :ivar start_ms: Inclusive session-relative start in milliseconds. Required on reflected + sideband events; omitted on the primary WebSocket. + :vartype start_ms: int + :ivar end_ms: Exclusive session-relative end in milliseconds. Required on reflected sideband + events; omitted on the primary WebSocket. Dropped output frames leave gaps between reflected + ranges. + :vartype end_ms: int + """ + + type: Literal[LiveServerEventType.SESSION_OUTPUT_AUDIO_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.output_audio.delta``. Required. SESSION_OUTPUT_AUDIO_DELTA.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64-encoded raw audio. Primary WebSocket events use the session's configured format; + reflected sideband events use mono PCM16LE at 24 kHz. Required.""" + start_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Inclusive session-relative start in milliseconds. Required on reflected sideband events; + omitted on the primary WebSocket.""" + end_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Exclusive session-relative end in milliseconds. Required on reflected sideband events; omitted + on the primary WebSocket. Dropped output frames leave gaps between reflected ranges.""" @overload def __init__( self, *, - protocol: Union[str, "_models.AgentEndpointProtocol"], - version: str, + delta: str, + start_ms: Optional[int] = None, + end_ms: Optional[int] = None, ) -> None: ... @overload @@ -16860,30 +17479,195 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.SESSION_OUTPUT_AUDIO_DELTA # type: ignore -class TelephonyTransferDestination(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A destination for a telephony transfer target. +class LiveProgrammaticToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveProgrammaticToolInputParam. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - PSTNTelephonyTransferDestination, SipTelephonyTransferDestination, - TeamsTelephonyTransferDestination + :ivar type: Required. Default value is "programmatic_tool_calling". + :vartype type: str + """ + + type: Literal["programmatic_tool_calling"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"programmatic_tool_calling\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["programmatic_tool_calling"] = "programmatic_tool_calling" - :ivar kind: The telephony transfer destination type. Required. Known values are: "pstn", - "teams", and "sip". - :vartype kind: str or ~azure.ai.projects.models.TelephonyTransferDestinationKind + +class LiveResponsesDelegationSettingsInputParam( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Model, prompt, and tool settings for tasks delegated by the Live session to a Responses + backend. + + :ivar model: The model used for server-owned Responses delegations. Required. + :vartype model: str + :ivar instructions: + :vartype instructions: str + :ivar max_output_tokens: + :vartype max_output_tokens: int + :ivar service_tier: Known values are: "auto", "default", "fast_tier_temp_pilot", "flex", + "priority", and "ultrafast". + :vartype service_tier: str or ~azure.ai.projects.models.LiveResponsesServiceTier + :ivar reasoning: + :vartype reasoning: ~azure.ai.projects.models.LiveDelegationReasoningInputParam + :ivar text: + :vartype text: ~azure.ai.projects.models.LiveDelegationTextInputParam + :ivar tools: Tools available to the Responses backend while it handles tasks delegated by the + Live model. + :vartype tools: list[~azure.ai.projects.models.LiveFunctionToolInputParam or + ~azure.ai.projects.models.LiveWebSearchToolInputParam or + ~azure.ai.projects.models.LiveFileSearchToolInputParam or + ~azure.ai.projects.models.LiveCodeInterpreterToolInputParam or + ~azure.ai.projects.models.LiveHostedShellToolInputParam or + ~azure.ai.projects.models.LiveImageGenerationToolInputParam or + ~azure.ai.projects.models.LiveMCPToolInputParam or + ~azure.ai.projects.models.LiveCustomToolInputParam or + ~azure.ai.projects.models.LiveNamespaceToolInputParam or + ~azure.ai.projects.models.LiveToolSearchToolInputParam or + ~azure.ai.projects.models.LiveProgrammaticToolInputParam or + ~azure.ai.projects.models.LiveComputerToolInputParam or + ~azure.ai.projects.models.LiveApplyPatchToolInputParam] + :ivar tool_choice: Controls which tool the Responses backend uses when handling a task + delegated by the Live model. Is one of the following types: Union[str, + "_models.LiveToolChoiceEnum"], LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, + LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, + LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, + LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, + LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam + :vartype tool_choice: str or ~azure.ai.projects.models.LiveToolChoiceEnum or + ~azure.ai.projects.models.LiveFunctionToolChoiceParam or + ~azure.ai.projects.models.LiveMCPToolChoiceParam or + ~azure.ai.projects.models.LiveSpecificFileSearchParam or + ~azure.ai.projects.models.LiveSpecificWebSearchParam or + ~azure.ai.projects.models.LiveSpecificWebSearchPreviewParam or + ~azure.ai.projects.models.LiveSpecificImageGenParam or + ~azure.ai.projects.models.LiveSpecificComputerParam or + ~azure.ai.projects.models.LiveSpecificCodeInterpreterParam or + ~azure.ai.projects.models.LiveSpecificProgrammaticToolCallingParam or + ~azure.ai.projects.models.LiveSpecificFunctionShellParam or + ~azure.ai.projects.models.LiveSpecificCustomToolParam or + ~azure.ai.projects.models.LiveSpecificApplyPatchParam or + ~azure.ai.projects.models.LiveAllowedToolsChoiceParam + :ivar parallel_tool_calls: + :vartype parallel_tool_calls: bool """ - __mapping__: dict[str, _Model] = {} - kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) - """The telephony transfer destination type. Required. Known values are: \"pstn\", \"teams\", and - \"sip\".""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model used for server-owned Responses delegations. Required.""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + max_output_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + service_tier: Optional[Union[str, "_models.LiveResponsesServiceTier"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"auto\", \"default\", \"fast_tier_temp_pilot\", \"flex\", \"priority\", and + \"ultrafast\".""" + reasoning: Optional["_models.LiveDelegationReasoningInputParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + text: Optional["_models.LiveDelegationTextInputParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + tools: Optional[ + list[ + Union[ + "_models.LiveFunctionToolInputParam", + "_models.LiveWebSearchToolInputParam", + "_models.LiveFileSearchToolInputParam", + "_models.LiveCodeInterpreterToolInputParam", + "_models.LiveHostedShellToolInputParam", + "_models.LiveImageGenerationToolInputParam", + "_models.LiveMCPToolInputParam", + "_models.LiveCustomToolInputParam", + "_models.LiveNamespaceToolInputParam", + "_models.LiveToolSearchToolInputParam", + "_models.LiveProgrammaticToolInputParam", + "_models.LiveComputerToolInputParam", + "_models.LiveApplyPatchToolInputParam", + ] + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Tools available to the Responses backend while it handles tasks delegated by the Live model.""" + tool_choice: Optional[ + Union[ + str, + "_models.LiveToolChoiceEnum", + "_models.LiveFunctionToolChoiceParam", + "_models.LiveMCPToolChoiceParam", + "_models.LiveSpecificFileSearchParam", + "_models.LiveSpecificWebSearchParam", + "_models.LiveSpecificWebSearchPreviewParam", + "_models.LiveSpecificImageGenParam", + "_models.LiveSpecificComputerParam", + "_models.LiveSpecificCodeInterpreterParam", + "_models.LiveSpecificProgrammaticToolCallingParam", + "_models.LiveSpecificFunctionShellParam", + "_models.LiveSpecificCustomToolParam", + "_models.LiveSpecificApplyPatchParam", + "_models.LiveAllowedToolsChoiceParam", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Controls which tool the Responses backend uses when handling a task delegated by the Live + model. Is one of the following types: Union[str, \"_models.LiveToolChoiceEnum\"], + LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, + LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, + LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, + LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, + LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam""" + parallel_tool_calls: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - kind: str, + model: str, + instructions: Optional[str] = None, + max_output_tokens: Optional[int] = None, + service_tier: Optional[Union[str, "_models.LiveResponsesServiceTier"]] = None, + reasoning: Optional["_models.LiveDelegationReasoningInputParam"] = None, + text: Optional["_models.LiveDelegationTextInputParam"] = None, + tools: Optional[ + list[ + Union[ + "_models.LiveFunctionToolInputParam", + "_models.LiveWebSearchToolInputParam", + "_models.LiveFileSearchToolInputParam", + "_models.LiveCodeInterpreterToolInputParam", + "_models.LiveHostedShellToolInputParam", + "_models.LiveImageGenerationToolInputParam", + "_models.LiveMCPToolInputParam", + "_models.LiveCustomToolInputParam", + "_models.LiveNamespaceToolInputParam", + "_models.LiveToolSearchToolInputParam", + "_models.LiveProgrammaticToolInputParam", + "_models.LiveComputerToolInputParam", + "_models.LiveApplyPatchToolInputParam", + ] + ] + ] = None, + tool_choice: Optional[ + Union[ + str, + "_models.LiveToolChoiceEnum", + "_models.LiveFunctionToolChoiceParam", + "_models.LiveMCPToolChoiceParam", + "_models.LiveSpecificFileSearchParam", + "_models.LiveSpecificWebSearchParam", + "_models.LiveSpecificWebSearchPreviewParam", + "_models.LiveSpecificImageGenParam", + "_models.LiveSpecificComputerParam", + "_models.LiveSpecificCodeInterpreterParam", + "_models.LiveSpecificProgrammaticToolCallingParam", + "_models.LiveSpecificFunctionShellParam", + "_models.LiveSpecificCustomToolParam", + "_models.LiveSpecificApplyPatchParam", + "_models.LiveAllowedToolsChoiceParam", + ] + ] = None, + parallel_tool_calls: Optional[bool] = None, ) -> None: ... @overload @@ -16897,28 +17681,179 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PSTNTelephonyTransferDestination( - TelephonyTransferDestination, discriminator="pstn" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A PSTN destination for a telephony transfer target. +class LiveResponsesDelegationSettingsUpdateInputParam( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Updates to the Responses backend of an existing Live session. Omitted settings retain their + current values. - :ivar kind: The PSTN destination type. Required. A public switched telephone network - destination. - :vartype kind: str or ~azure.ai.projects.models.PSTN - :ivar value: The E.164 phone number to call. Required. - :vartype value: str + :ivar model: The Responses backend model to use for subsequent delegated requests. Omit to keep + the current backend model. + :vartype model: str + :ivar instructions: + :vartype instructions: str + :ivar max_output_tokens: + :vartype max_output_tokens: int + :ivar service_tier: Known values are: "auto", "default", "fast_tier_temp_pilot", "flex", + "priority", and "ultrafast". + :vartype service_tier: str or ~azure.ai.projects.models.LiveResponsesServiceTier + :ivar reasoning: + :vartype reasoning: ~azure.ai.projects.models.LiveDelegationReasoningInputParam + :ivar text: + :vartype text: ~azure.ai.projects.models.LiveDelegationTextInputParam + :ivar tools: Tools available to the Responses backend while it handles tasks delegated by the + Live model. + :vartype tools: list[~azure.ai.projects.models.LiveFunctionToolInputParam or + ~azure.ai.projects.models.LiveWebSearchToolInputParam or + ~azure.ai.projects.models.LiveFileSearchToolInputParam or + ~azure.ai.projects.models.LiveCodeInterpreterToolInputParam or + ~azure.ai.projects.models.LiveHostedShellToolInputParam or + ~azure.ai.projects.models.LiveImageGenerationToolInputParam or + ~azure.ai.projects.models.LiveMCPToolInputParam or + ~azure.ai.projects.models.LiveCustomToolInputParam or + ~azure.ai.projects.models.LiveNamespaceToolInputParam or + ~azure.ai.projects.models.LiveToolSearchToolInputParam or + ~azure.ai.projects.models.LiveProgrammaticToolInputParam or + ~azure.ai.projects.models.LiveComputerToolInputParam or + ~azure.ai.projects.models.LiveApplyPatchToolInputParam] + :ivar tool_choice: Controls which tool the Responses backend uses when handling a task + delegated by the Live model. Is one of the following types: Union[str, + "_models.LiveToolChoiceEnum"], LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, + LiveSpecificFileSearchParam, LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, + LiveSpecificImageGenParam, LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, + LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, + LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam + :vartype tool_choice: str or ~azure.ai.projects.models.LiveToolChoiceEnum or + ~azure.ai.projects.models.LiveFunctionToolChoiceParam or + ~azure.ai.projects.models.LiveMCPToolChoiceParam or + ~azure.ai.projects.models.LiveSpecificFileSearchParam or + ~azure.ai.projects.models.LiveSpecificWebSearchParam or + ~azure.ai.projects.models.LiveSpecificWebSearchPreviewParam or + ~azure.ai.projects.models.LiveSpecificImageGenParam or + ~azure.ai.projects.models.LiveSpecificComputerParam or + ~azure.ai.projects.models.LiveSpecificCodeInterpreterParam or + ~azure.ai.projects.models.LiveSpecificProgrammaticToolCallingParam or + ~azure.ai.projects.models.LiveSpecificFunctionShellParam or + ~azure.ai.projects.models.LiveSpecificCustomToolParam or + ~azure.ai.projects.models.LiveSpecificApplyPatchParam or + ~azure.ai.projects.models.LiveAllowedToolsChoiceParam + :ivar parallel_tool_calls: + :vartype parallel_tool_calls: bool """ - kind: Literal[TelephonyTransferDestinationKind.PSTN] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The PSTN destination type. Required. A public switched telephone network destination.""" - value: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The E.164 phone number to call. Required.""" + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Responses backend model to use for subsequent delegated requests. Omit to keep the current + backend model.""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + max_output_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + service_tier: Optional[Union[str, "_models.LiveResponsesServiceTier"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"auto\", \"default\", \"fast_tier_temp_pilot\", \"flex\", \"priority\", and + \"ultrafast\".""" + reasoning: Optional["_models.LiveDelegationReasoningInputParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + text: Optional["_models.LiveDelegationTextInputParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + tools: Optional[ + list[ + Union[ + "_models.LiveFunctionToolInputParam", + "_models.LiveWebSearchToolInputParam", + "_models.LiveFileSearchToolInputParam", + "_models.LiveCodeInterpreterToolInputParam", + "_models.LiveHostedShellToolInputParam", + "_models.LiveImageGenerationToolInputParam", + "_models.LiveMCPToolInputParam", + "_models.LiveCustomToolInputParam", + "_models.LiveNamespaceToolInputParam", + "_models.LiveToolSearchToolInputParam", + "_models.LiveProgrammaticToolInputParam", + "_models.LiveComputerToolInputParam", + "_models.LiveApplyPatchToolInputParam", + ] + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Tools available to the Responses backend while it handles tasks delegated by the Live model.""" + tool_choice: Optional[ + Union[ + str, + "_models.LiveToolChoiceEnum", + "_models.LiveFunctionToolChoiceParam", + "_models.LiveMCPToolChoiceParam", + "_models.LiveSpecificFileSearchParam", + "_models.LiveSpecificWebSearchParam", + "_models.LiveSpecificWebSearchPreviewParam", + "_models.LiveSpecificImageGenParam", + "_models.LiveSpecificComputerParam", + "_models.LiveSpecificCodeInterpreterParam", + "_models.LiveSpecificProgrammaticToolCallingParam", + "_models.LiveSpecificFunctionShellParam", + "_models.LiveSpecificCustomToolParam", + "_models.LiveSpecificApplyPatchParam", + "_models.LiveAllowedToolsChoiceParam", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Controls which tool the Responses backend uses when handling a task delegated by the Live + model. Is one of the following types: Union[str, \"_models.LiveToolChoiceEnum\"], + LiveFunctionToolChoiceParam, LiveMCPToolChoiceParam, LiveSpecificFileSearchParam, + LiveSpecificWebSearchParam, LiveSpecificWebSearchPreviewParam, LiveSpecificImageGenParam, + LiveSpecificComputerParam, LiveSpecificCodeInterpreterParam, + LiveSpecificProgrammaticToolCallingParam, LiveSpecificFunctionShellParam, + LiveSpecificCustomToolParam, LiveSpecificApplyPatchParam, LiveAllowedToolsChoiceParam""" + parallel_tool_calls: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - value: str, + model: Optional[str] = None, + instructions: Optional[str] = None, + max_output_tokens: Optional[int] = None, + service_tier: Optional[Union[str, "_models.LiveResponsesServiceTier"]] = None, + reasoning: Optional["_models.LiveDelegationReasoningInputParam"] = None, + text: Optional["_models.LiveDelegationTextInputParam"] = None, + tools: Optional[ + list[ + Union[ + "_models.LiveFunctionToolInputParam", + "_models.LiveWebSearchToolInputParam", + "_models.LiveFileSearchToolInputParam", + "_models.LiveCodeInterpreterToolInputParam", + "_models.LiveHostedShellToolInputParam", + "_models.LiveImageGenerationToolInputParam", + "_models.LiveMCPToolInputParam", + "_models.LiveCustomToolInputParam", + "_models.LiveNamespaceToolInputParam", + "_models.LiveToolSearchToolInputParam", + "_models.LiveProgrammaticToolInputParam", + "_models.LiveComputerToolInputParam", + "_models.LiveApplyPatchToolInputParam", + ] + ] + ] = None, + tool_choice: Optional[ + Union[ + str, + "_models.LiveToolChoiceEnum", + "_models.LiveFunctionToolChoiceParam", + "_models.LiveMCPToolChoiceParam", + "_models.LiveSpecificFileSearchParam", + "_models.LiveSpecificWebSearchParam", + "_models.LiveSpecificWebSearchPreviewParam", + "_models.LiveSpecificImageGenParam", + "_models.LiveSpecificComputerParam", + "_models.LiveSpecificCodeInterpreterParam", + "_models.LiveSpecificProgrammaticToolCallingParam", + "_models.LiveSpecificFunctionShellParam", + "_models.LiveSpecificCustomToolParam", + "_models.LiveSpecificApplyPatchParam", + "_models.LiveAllowedToolsChoiceParam", + ] + ] = None, + parallel_tool_calls: Optional[bool] = None, ) -> None: ... @overload @@ -16930,37 +17865,49 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = TelephonyTransferDestinationKind.PSTN # type: ignore -class RaiConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Configuration for Responsible AI (RAI) content filtering and safety features. +class LiveResponsesDelegationUpdateParam( + LiveSessionUpdateParamsDelegation, discriminator="responses" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Update the Responses backend for an existing Live session without changing delegation + ownership. - :ivar rai_policy_name: The name of the RAI policy to apply. Required. - :vartype rai_policy_name: str - :ivar invocations_moderation: Author-declared configuration telling the platform where - user/agent text lives in the agent-defined invocations request/response bodies, so - content-safety guardrails can extract and moderate it. Optional; a rai_config without it leaves - the invocations path without content-safety moderation. - :vartype invocations_moderation: ~azure.ai.projects.models.RaiInvocationModeration + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: The delegation owner. Always ``responses`` for tasks handled by the Responses API. + Required. RESPONSES. + :vartype type: str or ~azure.ai.projects.models.RESPONSES + :ivar responses: Responses backend settings to update. Omitted settings keep their existing + values. + :vartype responses: ~azure.ai.projects.models.LiveResponsesDelegationSettingsUpdateInputParam """ - rai_policy_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the RAI policy to apply. Required.""" - invocations_moderation: Optional["_models.RaiInvocationModeration"] = rest_field( + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + type: Literal[LiveSessionUpdateParamsDelegationType.RESPONSES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The delegation owner. Always ``responses`` for tasks handled by the Responses API. Required. + RESPONSES.""" + responses: Optional["_models.LiveResponsesDelegationSettingsUpdateInputParam"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Author-declared configuration telling the platform where user/agent text lives in the - agent-defined invocations request/response bodies, so content-safety guardrails can extract and - moderate it. Optional; a rai_config without it leaves the invocations path without - content-safety moderation.""" + """Responses backend settings to update. Omitted settings keep their existing values.""" @overload def __init__( self, *, - rai_policy_name: str, - invocations_moderation: Optional["_models.RaiInvocationModeration"] = None, + acknowledgement_delay_ms: Optional[int] = None, + responses: Optional["_models.LiveResponsesDelegationSettingsUpdateInputParam"] = None, ) -> None: ... @overload @@ -16972,67 +17919,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveSessionUpdateParamsDelegationType.RESPONSES # type: ignore -class RaiInvocationModeration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Declares where request/response text lives so content-safety guardrails can extract it. +class LiveServerEventLiveCommentaryAppended( + LiveServerEvent, discriminator="session.commentary.appended" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a session.commentary.append command is accepted into the Live session timeline. + Acknowledges the added commentary without guaranteeing exact wording or completed audio + playback. - :ivar input_content_type: How the REQUEST body is parsed. When omitted, the service defaults to - ``json``. Known values are: "json" and "text". - :vartype input_content_type: str or ~azure.ai.projects.models.RaiInvocationContentType - :ivar output_content_type: How the RESPONSE body is parsed. When omitted, the service defaults - to ``json``. Known values are: "json" and "text". - :vartype output_content_type: str or ~azure.ai.projects.models.RaiInvocationContentType - :ivar response_mode: Author-declared response shape; drives which output gate runs and which - fields are required. Required. Known values are: "non_streaming", "streaming", and "both". - :vartype response_mode: str or ~azure.ai.projects.models.RaiInvocationMode - :ivar input_paths: Path(s) to user text in the REQUEST body. Required when input_content_type - is ``json``. - :vartype input_paths: list[str] - :ivar output_paths: Path(s) to agent text in a NON-STREAMING response body. Required when - response_mode is non_streaming/both and output_content_type is ``json``. - :vartype output_paths: list[str] - :ivar stream_selectors: One SSE event->field selector per event type carrying text. Required - when response_mode is streaming/both and output_content_type is ``json``. - :vartype stream_selectors: list[~azure.ai.projects.models.RaiSseTextSelector] + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar start_ms: The start of this event on the Live session timeline, in milliseconds from the + beginning of the session. Required. + :vartype start_ms: int + :ivar end_ms: The end of this event on the Live session timeline, in milliseconds from the + beginning of the session. For appended context, this can equal start_ms. Required. + :vartype end_ms: int + :ivar type: The event type, always ``session.commentary.appended``. Required. + SESSION_COMMENTARY_APPENDED. + :vartype type: str or ~azure.ai.projects.models.SESSION_COMMENTARY_APPENDED """ - input_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """How the REQUEST body is parsed. When omitted, the service defaults to ``json``. Known values - are: \"json\" and \"text\".""" - output_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """How the RESPONSE body is parsed. When omitted, the service defaults to ``json``. Known values - are: \"json\" and \"text\".""" - response_mode: Union[str, "_models.RaiInvocationMode"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Author-declared response shape; drives which output gate runs and which fields are required. - Required. Known values are: \"non_streaming\", \"streaming\", and \"both\".""" - input_paths: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Path(s) to user text in the REQUEST body. Required when input_content_type is ``json``.""" - output_paths: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Path(s) to agent text in a NON-STREAMING response body. Required when response_mode is - non_streaming/both and output_content_type is ``json``.""" - stream_selectors: Optional[list["_models.RaiSseTextSelector"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """One SSE event->field selector per event type carrying text. Required when response_mode is - streaming/both and output_content_type is ``json``.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The start of this event on the Live session timeline, in milliseconds from the beginning of the + session. Required.""" + end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The end of this event on the Live session timeline, in milliseconds from the beginning of the + session. For appended context, this can equal start_ms. Required.""" + type: Literal[LiveServerEventType.SESSION_COMMENTARY_APPENDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.commentary.appended``. Required. SESSION_COMMENTARY_APPENDED.""" @overload def __init__( self, *, - response_mode: Union[str, "_models.RaiInvocationMode"], - input_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = None, - output_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = None, - input_paths: Optional[list[str]] = None, - output_paths: Optional[list[str]] = None, - stream_selectors: Optional[list["_models.RaiSseTextSelector"]] = None, + event_id: str, + start_ms: int, + end_ms: int, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17044,30 +17977,60 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.SESSION_COMMENTARY_APPENDED # type: ignore -class RaiSseTextSelector(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """An SSE event-type to text-field selector for streaming invocation output. - - :ivar event_type: The SSE event ``type`` value that carries text. Required. - :vartype event_type: str - :ivar text_field: The field on a matched event holding the text delta. When omitted, the - service defaults to ``delta``. - :vartype text_field: str - """ +class LiveServerEventLiveDecisionEvent( + LiveServerEvent, discriminator="decision.event" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Decision API event for a Live delegation or transcript trigger. For a trigger, + source_event_id identifies the transcript delta that caused this evaluation. - event_type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The SSE event ``type`` value that carries text. Required.""" - text_field: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The field on a matched event holding the text delta. When omitted, the service defaults to - ``delta``.""" + :ivar type: Required. DECISION_EVENT. + :vartype type: str or ~azure.ai.projects.models.DECISION_EVENT + :ivar event_id: The unique ID of this Live server event. Required. + :vartype event_id: str + :ivar delegation_id: Required. + :vartype delegation_id: str + :ivar trigger_id: Required. + :vartype trigger_id: str + :ivar source_event_type: Required. Is either a Literal["session.input_transcript.delta"] type + or a Literal["session.output_transcript.delta"] type. + :vartype source_event_type: str or str + :ivar source_event_id: Required. + :vartype source_event_id: str + :ivar event: Required. + :vartype event: ~azure.ai.projects.models.LiveDecisionCompleted + """ + + type: Literal[LiveServerEventType.DECISION_EVENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISION_EVENT.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of this Live server event. Required.""" + delegation_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + trigger_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + source_event_type: Literal["session.input_transcript.delta", "session.output_transcript.delta"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required. Is either a Literal[\"session.input_transcript.delta\"] type or a + Literal[\"session.output_transcript.delta\"] type.""" + source_event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + event: "_models.LiveDecisionCompleted" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - event_type: str, - text_field: Optional[str] = None, + event_id: str, + delegation_id: str, + trigger_id: str, + source_event_type: Literal["session.input_transcript.delta", "session.output_transcript.delta"], + source_event_id: str, + event: "_models.LiveDecisionCompleted", ) -> None: ... @overload @@ -17079,43 +18042,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.DECISION_EVENT # type: ignore -class RankingOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RankingOptions. +class LiveServerEventLiveDecisionItemCreated( + LiveServerEvent, discriminator="decision.item.created" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An input item was appended for future decisions. - :ivar ranker: The ranker to use for the file search. Known values are: "auto" and - "default-2024-11-15". - :vartype ranker: str or ~azure.ai.projects.models.RankerVersionType - :ivar score_threshold: The score threshold for the file search, a number between 0 and 1. - Numbers closer to 1 will attempt to return only the most relevant results, but may return fewer - results. - :vartype score_threshold: float - :ivar hybrid_search: Weights that control how reciprocal rank fusion balances semantic - embedding matches versus sparse keyword matches when hybrid search is enabled. - :vartype hybrid_search: ~azure.ai.projects.models.HybridSearchOptions + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: Required. DECISION_ITEM_CREATED. + :vartype type: str or ~azure.ai.projects.models.DECISION_ITEM_CREATED + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.LiveDecisionStoredInputItemParam """ - ranker: Optional[Union[str, "_models.RankerVersionType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The ranker to use for the file search. Known values are: \"auto\" and \"default-2024-11-15\".""" - score_threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The score threshold for the file search, a number between 0 and 1. Numbers closer to 1 will - attempt to return only the most relevant results, but may return fewer results.""" - hybrid_search: Optional["_models.HybridSearchOptions"] = rest_field( + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.DECISION_ITEM_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISION_ITEM_CREATED.""" + item: "_models.LiveDecisionStoredInputItemParam" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Weights that control how reciprocal rank fusion balances semantic embedding matches versus - sparse keyword matches when hybrid search is enabled.""" + """Required.""" @overload def __init__( self, *, - ranker: Optional[Union[str, "_models.RankerVersionType"]] = None, - score_threshold: Optional[float] = None, - hybrid_search: Optional["_models.HybridSearchOptions"] = None, + event_id: str, + item: "_models.LiveDecisionStoredInputItemParam", + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17127,27 +18090,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.DECISION_ITEM_CREATED # type: ignore -class RealtimeAudioFormats(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeAudioFormats. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - RealtimeAudioFormatsAudioPcm, RealtimeAudioFormatsAudioPcma, RealtimeAudioFormatsAudioPcmu +class LiveServerEventLiveDecisionItemDeleted( + LiveServerEvent, discriminator="decision.item.deleted" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An input item was removed from future decisions. - :ivar type: Required. Known values are: "audio/pcm", "audio/pcmu", and "audio/pcma". - :vartype type: str or ~azure.ai.projects.models.RealtimeAudioFormatsType + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: Required. DECISION_ITEM_DELETED. + :vartype type: str or ~azure.ai.projects.models.DECISION_ITEM_DELETED + :ivar item_id: Required. + :vartype item_id: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"audio/pcm\", \"audio/pcmu\", and \"audio/pcma\".""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.DECISION_ITEM_DELETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISION_ITEM_DELETED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - type: str, + event_id: str, + item_id: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17159,29 +18136,55 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.DECISION_ITEM_DELETED # type: ignore -class RealtimeAudioFormatsAudioPcm( - RealtimeAudioFormats, discriminator="audio/pcm" +class LiveServerEventLiveDelegationCreated( + LiveServerEvent, discriminator="session.delegation.created" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeAudioFormatsAudioPcm. + """Returned when the Live model delegates work to your application, Responses, or Decisions. + Contains delegation metadata and the position on the session timeline where the work was + delegated. - :ivar type: Required. AUDIO_PCM. - :vartype type: str or ~azure.ai.projects.models.AUDIO_PCM - :ivar rate: Default value is 24000. - :vartype rate: int + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``session.delegation.created``. Required. + SESSION_DELEGATION_CREATED. + :vartype type: str or ~azure.ai.projects.models.SESSION_DELEGATION_CREATED + :ivar offset_ms: The position on the Live session timeline where the delegation was created, in + milliseconds from the beginning of the session. Required. + :vartype offset_ms: int + :ivar delegation: The delegated work identifier and destination. This object contains metadata, + not the task text. Required. + :vartype delegation: ~azure.ai.projects.models.VoiceAgentLiveDelegationItem """ - type: Literal[RealtimeAudioFormatsType.AUDIO_PCM] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. AUDIO_PCM.""" - rate: Optional[Literal[24000]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Default value is 24000.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_DELEGATION_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.delegation.created``. Required. SESSION_DELEGATION_CREATED.""" + offset_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The position on the Live session timeline where the delegation was created, in milliseconds + from the beginning of the session. Required.""" + delegation: "_models.VoiceAgentLiveDelegationItem" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The delegated work identifier and destination. This object contains metadata, not the task + text. Required.""" @overload def __init__( self, *, - rate: Optional[Literal[24000]] = None, + event_id: str, + offset_ms: int, + delegation: "_models.VoiceAgentLiveDelegationItem", + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17193,22 +18196,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeAudioFormatsType.AUDIO_PCM # type: ignore + self.type = LiveServerEventType.SESSION_DELEGATION_CREATED # type: ignore -class RealtimeAudioFormatsAudioPcma(RealtimeAudioFormats, discriminator="audio/pcma"): - """RealtimeAudioFormatsAudioPcma. +class LiveServerEventLiveErrorEvent( + LiveServerEvent, discriminator="error" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reports an error in the Live session, such as an invalid client command. Use + error.client_event_id, when present, to identify the command that caused the error. - :ivar type: Required. AUDIO_PCMA. - :vartype type: str or ~azure.ai.projects.models.AUDIO_PCMA + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``error``. Required. ERROR. + :vartype type: str or ~azure.ai.projects.models.ERROR + :ivar error: Details of the Live error and the client command that caused it, when known. + Required. + :vartype error: ~azure.ai.projects.models.LiveLiveError """ - type: Literal[RealtimeAudioFormatsType.AUDIO_PCMA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. AUDIO_PCMA.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``error``. Required. ERROR.""" + error: "_models.LiveLiveError" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Details of the Live error and the client command that caused it, when known. Required.""" @overload def __init__( self, + *, + event_id: str, + error: "_models.LiveLiveError", + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17220,22 +18244,48 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeAudioFormatsType.AUDIO_PCMA # type: ignore + self.type = LiveServerEventType.ERROR # type: ignore -class RealtimeAudioFormatsAudioPcmu(RealtimeAudioFormats, discriminator="audio/pcmu"): - """RealtimeAudioFormatsAudioPcmu. +class LiveServerEventLiveInfoEvent( + LiveServerEvent, discriminator="info" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An informational notice about the Live session, such as the event permissions applied to a + frontend data channel. - :ivar type: Required. AUDIO_PCMU. - :vartype type: str or ~azure.ai.projects.models.AUDIO_PCMU + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``info``. Required. INFO. + :vartype type: str or ~azure.ai.projects.models.INFO + :ivar code: A machine-readable code for the notice, such as ``data_channel_permissions``. + Required. + :vartype code: str + :ivar message: A human-readable explanation of the Live session notice. Required. + :vartype message: str """ - type: Literal[RealtimeAudioFormatsType.AUDIO_PCMU] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. AUDIO_PCMU.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.INFO] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``info``. Required. INFO.""" + code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A machine-readable code for the notice, such as ``data_channel_permissions``. Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable explanation of the Live session notice. Required.""" @overload def __init__( self, + *, + event_id: str, + code: str, + message: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17247,41 +18297,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeAudioFormatsType.AUDIO_PCMU # type: ignore - + self.type = LiveServerEventType.INFO # type: ignore -class RealtimeClientEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A realtime client event. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - RealtimeClientEventConversationItemCreate, RealtimeClientEventConversationItemDelete, - RealtimeClientEventConversationItemRetrieve, RealtimeClientEventConversationItemTruncate, - RealtimeClientEventInputAudioBufferAppend, RealtimeClientEventInputAudioBufferClear, - RealtimeClientEventInputAudioBufferCommit, RealtimeClientEventOutputAudioBufferClear, - RealtimeClientEventResponseCancel, RealtimeClientEventResponseCreate, - VoiceAgentClientEventRtcCallSdpCreate, VoiceAgentClientEventSessionAvatarConnect +class LiveServerEventLiveInputAudioMuted( + LiveServerEvent, discriminator="session.input_audio.muted" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Acknowledges a session.input_audio.mute command. An independent input mute sends silence to the + model and preserves sideband audio reflection. Fixture playback does not emit this event. - :ivar type: Required. Known values are: "conversation.item.create", "conversation.item.delete", - "conversation.item.retrieve", "conversation.item.truncate", "input_audio_buffer.append", - "input_audio_buffer.clear", "output_audio_buffer.clear", "input_audio_buffer.commit", - "response.cancel", "response.create", "session.update", "session.avatar.connect", and - "rtc.call.sdp.create". - :vartype type: str or ~azure.ai.projects.models.RealtimeClientEventType + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``session.input_audio.muted``. Required. + SESSION_INPUT_AUDIO_MUTED. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_AUDIO_MUTED """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"conversation.item.create\", \"conversation.item.delete\", - \"conversation.item.retrieve\", \"conversation.item.truncate\", \"input_audio_buffer.append\", - \"input_audio_buffer.clear\", \"output_audio_buffer.clear\", \"input_audio_buffer.commit\", - \"response.cancel\", \"response.create\", \"session.update\", \"session.avatar.connect\", and - \"rtc.call.sdp.create\".""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_INPUT_AUDIO_MUTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.input_audio.muted``. Required. SESSION_INPUT_AUDIO_MUTED.""" @overload def __init__( self, *, - type: str, + event_id: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17293,52 +18340,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.SESSION_INPUT_AUDIO_MUTED # type: ignore -class RealtimeClientEventConversationItemCreate( - RealtimeClientEvent, discriminator="conversation.item.create" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Add a new Item to the Conversation's context, including messages, function calls, and function - call responses. This event can be used both to populate a "history" of the conversation and to - add new items mid-stream, but has the current limitation that it cannot populate assistant - audio messages. If successful, the server will respond with a ``conversation.item.created`` - event, otherwise an ``error`` event will be sent. +class LiveServerEventLiveInputAudioUnmuted( + LiveServerEvent, discriminator="session.input_audio.unmuted" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Acknowledges a session.input_audio.unmute command, removing the independent input mute. An + active audio fixture still pauses inference until playback finishes. Fixture playback does not + emit this event. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.create``. Required. - CONVERSATION_ITEM_CREATE. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_CREATE - :ivar previous_item_id: The ID of the preceding item after which the new item will be inserted. - If not set, the new item will be appended to the end of the conversation. If set to ``root``, - the new item will be added to the beginning of the conversation. If set to an existing ID, it - allows an item to be inserted mid-conversation. If the ID cannot be found, an error will be - returned and the item will not be added. - :vartype previous_item_id: str - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``session.input_audio.unmuted``. Required. + SESSION_INPUT_AUDIO_UNMUTED. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_AUDIO_UNMUTED """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.create``. Required. CONVERSATION_ITEM_CREATE.""" - previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the preceding item after which the new item will be inserted. If not set, the new - item will be appended to the end of the conversation. If set to ``root``, the new item will be - added to the beginning of the conversation. If set to an existing ID, it allows an item to be - inserted mid-conversation. If the ID cannot be found, an error will be returned and the item - will not be added.""" - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_INPUT_AUDIO_UNMUTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.input_audio.unmuted``. Required. SESSION_INPUT_AUDIO_UNMUTED.""" @overload def __init__( self, *, - item: "_models.RealtimeConversationItem", - event_id: Optional[str] = None, - previous_item_id: Optional[str] = None, + event_id: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17350,38 +18384,60 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.CONVERSATION_ITEM_CREATE # type: ignore + self.type = LiveServerEventType.SESSION_INPUT_AUDIO_UNMUTED # type: ignore -class RealtimeClientEventConversationItemDelete( - RealtimeClientEvent, discriminator="conversation.item.delete" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Send this event when you want to remove any item from the conversation history. The server will - respond with a ``conversation.item.deleted`` event, unless the item does not exist in the - conversation history, in which case the server will respond with an error. +class LiveServerEventLiveInputTranscriptDelta( + LiveServerEvent, discriminator="session.input_transcript.delta" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A transcript fragment for user input audio in the Live session. Accumulate fragments in + delivery order; these events do not define complete turns or include a transcript-done event. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.delete``. Required. - CONVERSATION_ITEM_DELETE. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_DELETE - :ivar item_id: The ID of the item to delete. Required. - :vartype item_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar start_ms: The start of this event on the Live session timeline, in milliseconds from the + beginning of the session. Required. + :vartype start_ms: int + :ivar end_ms: The end of this event on the Live session timeline, in milliseconds from the + beginning of the session. For appended context, this can equal start_ms. Required. + :vartype end_ms: int + :ivar delta: The transcript text fragment for the audio in this time range. Append fragments in + delivery order to build the transcript. Required. + :vartype delta: str + :ivar type: The event type, always ``session.input_transcript.delta``. Required. + SESSION_INPUT_TRANSCRIPT_DELTA. + :vartype type: str or ~azure.ai.projects.models.SESSION_INPUT_TRANSCRIPT_DELTA """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_DELETE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.delete``. Required. CONVERSATION_ITEM_DELETE.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item to delete. Required.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The start of this event on the Live session timeline, in milliseconds from the beginning of the + session. Required.""" + end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The end of this event on the Live session timeline, in milliseconds from the beginning of the + session. For appended context, this can equal start_ms. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The transcript text fragment for the audio in this time range. Append fragments in delivery + order to build the transcript. Required.""" + type: Literal[LiveServerEventType.SESSION_INPUT_TRANSCRIPT_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.input_transcript.delta``. Required. + SESSION_INPUT_TRANSCRIPT_DELTA.""" @overload def __init__( self, *, - item_id: str, - event_id: Optional[str] = None, + event_id: str, + start_ms: int, + end_ms: int, + delta: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17393,40 +18449,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.CONVERSATION_ITEM_DELETE # type: ignore + self.type = LiveServerEventType.SESSION_INPUT_TRANSCRIPT_DELTA # type: ignore -class RealtimeClientEventConversationItemRetrieve( - RealtimeClientEvent, discriminator="conversation.item.retrieve" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Send this event when you want to retrieve the server's representation of a specific item in the - conversation history. This is useful, for example, to inspect user audio after noise - cancellation and VAD. The server will respond with a ``conversation.item.retrieved`` event, - unless the item does not exist in the conversation history, in which case the server will - respond with an error. +class LiveServerEventLiveInstructionsAppended( + LiveServerEvent, discriminator="session.instructions.appended" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a session.instructions.append command is accepted into the Live session timeline. + Acknowledges the appended instructions without guaranteeing that the model has acted on them. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.retrieve``. Required. - CONVERSATION_ITEM_RETRIEVE. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_RETRIEVE - :ivar item_id: The ID of the item to retrieve. Required. - :vartype item_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar start_ms: The start of this event on the Live session timeline, in milliseconds from the + beginning of the session. Required. + :vartype start_ms: int + :ivar end_ms: The end of this event on the Live session timeline, in milliseconds from the + beginning of the session. For appended context, this can equal start_ms. Required. + :vartype end_ms: int + :ivar type: The event type, always ``session.instructions.appended``. Required. + SESSION_INSTRUCTIONS_APPENDED. + :vartype type: str or ~azure.ai.projects.models.SESSION_INSTRUCTIONS_APPENDED """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_RETRIEVE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.retrieve``. Required. CONVERSATION_ITEM_RETRIEVE.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item to retrieve. Required.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The start of this event on the Live session timeline, in milliseconds from the beginning of the + session. Required.""" + end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The end of this event on the Live session timeline, in milliseconds from the beginning of the + session. For appended context, this can equal start_ms. Required.""" + type: Literal[LiveServerEventType.SESSION_INSTRUCTIONS_APPENDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.instructions.appended``. Required. + SESSION_INSTRUCTIONS_APPENDED.""" @overload def __init__( self, *, - item_id: str, - event_id: Optional[str] = None, + event_id: str, + start_ms: int, + end_ms: int, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17438,57 +18507,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.CONVERSATION_ITEM_RETRIEVE # type: ignore + self.type = LiveServerEventType.SESSION_INSTRUCTIONS_APPENDED # type: ignore -class RealtimeClientEventConversationItemTruncate( - RealtimeClientEvent, discriminator="conversation.item.truncate" +class LiveServerEventLiveOutputAudioFixturePlayed( + LiveServerEvent, discriminator="session.output_audio.fixture.played" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Send this event to truncate a previous assistant message’s audio. The server will produce audio - faster than realtime, so this event is useful when the user interrupts to truncate audio that - has already been sent to the client but not yet played. This will synchronize the server's - understanding of the audio with the client's playback. Truncating audio will delete the - server-side text transcript to ensure there is not text in the context that hasn't been heard - by the user. If successful, the server will respond with a ``conversation.item.truncated`` - event. + """The complete audio fixture has drained from the server mixer and normal inference has resumed. + Transport buffers may still contain audio; this event does not prove listener-side completion. + The optional client_event_id echoes the play command. This event is not emitted for canceled or + failed playback. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.truncate``. Required. - CONVERSATION_ITEM_TRUNCATE. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_TRUNCATE - :ivar item_id: The ID of the assistant message item to truncate. Only assistant message items - can be truncated. Required. - :vartype item_id: str - :ivar content_index: The index of the content part to truncate. Set this to ``0``. Required. - :vartype content_index: int - :ivar audio_end_ms: Inclusive duration up to which audio is truncated, in milliseconds. If the - audio_end_ms is greater than the actual audio duration, the server will respond with an error. - Required. - :vartype audio_end_ms: int + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: Required. SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED. + :vartype type: str or ~azure.ai.projects.models.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_TRUNCATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.truncate``. Required. CONVERSATION_ITEM_TRUNCATE.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the assistant message item to truncate. Only assistant message items can be - truncated. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part to truncate. Set this to ``0``. Required.""" - audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Inclusive duration up to which audio is truncated, in milliseconds. If the audio_end_ms is - greater than the actual audio duration, the server will respond with an error. Required.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED.""" @overload def __init__( self, *, - item_id: str, - content_index: int, - audio_end_ms: int, - event_id: Optional[str] = None, + event_id: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17500,47 +18551,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.CONVERSATION_ITEM_TRUNCATE # type: ignore + self.type = LiveServerEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYED # type: ignore -class RealtimeClientEventInputAudioBufferAppend( - RealtimeClientEvent, discriminator="input_audio_buffer.append" +class LiveServerEventLiveOutputAudioFixturePlaying( + LiveServerEvent, discriminator="session.output_audio.fixture.playing" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Send this event to append audio bytes to the input audio buffer. The audio buffer is temporary - storage you can write to and later commit. A "commit" will create a new user message item in - the conversation history from the buffer content and clear the buffer. Input audio - transcription (if enabled) will be generated when the buffer is committed. If VAD is enabled - the audio buffer is used to detect speech and the server will decide when to commit. When - Server VAD is disabled, you must commit the audio buffer manually. Input audio noise reduction - operates on writes to the audio buffer. The client may choose how much audio to place in each - event up to a maximum of 15 MiB, for example streaming smaller chunks from the client may allow - the VAD to be more responsive. Unlike most other client events, the server will not send a - confirmation response to this event. + """The existing playback path has accepted the validated audio fixture. This acknowledgment does + not identify when the listener receives the first sample. The optional client_event_id echoes + the play command. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.append``. Required. - INPUT_AUDIO_BUFFER_APPEND. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_APPEND - :ivar audio: Base64-encoded audio bytes. This must be in the format specified by the - ``input_audio_format`` field in the session configuration. Required. - :vartype audio: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: Required. SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING. + :vartype type: str or ~azure.ai.projects.models.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.append``. Required. INPUT_AUDIO_BUFFER_APPEND.""" - audio: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Base64-encoded audio bytes. This must be in the format specified by the ``input_audio_format`` - field in the session configuration. Required.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING.""" @overload def __init__( self, *, - audio: str, - event_id: Optional[str] = None, + event_id: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17552,32 +18594,60 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.INPUT_AUDIO_BUFFER_APPEND # type: ignore + self.type = LiveServerEventType.SESSION_OUTPUT_AUDIO_FIXTURE_PLAYING # type: ignore -class RealtimeClientEventInputAudioBufferClear( - RealtimeClientEvent, discriminator="input_audio_buffer.clear" +class LiveServerEventLiveOutputTranscriptDelta( + LiveServerEvent, discriminator="session.output_transcript.delta" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Send this event to clear the audio bytes in the buffer. The server will respond with an - ``input_audio_buffer.cleared`` event. + """A transcript fragment for assistant output audio in the Live session. Accumulate fragments in + delivery order; these events do not define complete turns or include a transcript-done event. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.clear``. Required. - INPUT_AUDIO_BUFFER_CLEAR. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_CLEAR + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar start_ms: The start of this event on the Live session timeline, in milliseconds from the + beginning of the session. Required. + :vartype start_ms: int + :ivar end_ms: The end of this event on the Live session timeline, in milliseconds from the + beginning of the session. For appended context, this can equal start_ms. Required. + :vartype end_ms: int + :ivar delta: The transcript text fragment for the audio in this time range. Append fragments in + delivery order to build the transcript. Required. + :vartype delta: str + :ivar type: The event type, always ``session.output_transcript.delta``. Required. + SESSION_OUTPUT_TRANSCRIPT_DELTA. + :vartype type: str or ~azure.ai.projects.models.SESSION_OUTPUT_TRANSCRIPT_DELTA """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_CLEAR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.clear``. Required. INPUT_AUDIO_BUFFER_CLEAR.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The start of this event on the Live session timeline, in milliseconds from the beginning of the + session. Required.""" + end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The end of this event on the Live session timeline, in milliseconds from the beginning of the + session. For appended context, this can equal start_ms. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The transcript text fragment for the audio in this time range. Append fragments in delivery + order to build the transcript. Required.""" + type: Literal[LiveServerEventType.SESSION_OUTPUT_TRANSCRIPT_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.output_transcript.delta``. Required. + SESSION_OUTPUT_TRANSCRIPT_DELTA.""" @overload def __init__( self, *, - event_id: Optional[str] = None, + event_id: str, + start_ms: int, + end_ms: int, + delta: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17589,36 +18659,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.INPUT_AUDIO_BUFFER_CLEAR # type: ignore + self.type = LiveServerEventType.SESSION_OUTPUT_TRANSCRIPT_DELTA # type: ignore -class RealtimeClientEventInputAudioBufferCommit( - RealtimeClientEvent, discriminator="input_audio_buffer.commit" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Send this event to commit the user input audio buffer, which will create a new user message - item in the conversation. This event will produce an error if the input audio buffer is empty. - When in Server VAD mode, the client does not need to send this event, the server will commit - the audio buffer automatically. Committing the input audio buffer will trigger input audio - transcription (if enabled in session configuration), but it will not create a response from - the model. The server will respond with an ``input_audio_buffer.committed`` event. +class LiveServerEventLiveResponseEvent( + LiveServerEvent, discriminator="response.event" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A streaming Responses API event from a backend delegated to by the Live session. Use the outer + delegation_id to associate the nested stream with its Live delegation. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.commit``. Required. - INPUT_AUDIO_BUFFER_COMMIT. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_COMMIT + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``response.event``. Required. RESPONSE_EVENT. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_EVENT + :ivar delegation_id: + :vartype delegation_id: str + :ivar event: The nested Responses streaming event. Dispatch on its type field. Response + lifecycle snapshots omit input and clear instructions, tools, and output to keep messages + small; consume granular output events for the generated content. Required. + :vartype event: dict[str, any] """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_COMMIT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.commit``. Required. INPUT_AUDIO_BUFFER_COMMIT.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.RESPONSE_EVENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``response.event``. Required. RESPONSE_EVENT.""" + delegation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + event: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The nested Responses streaming event. Dispatch on its type field. Response lifecycle snapshots + omit input and clear instructions, tools, and output to keep messages small; consume granular + output events for the generated content. Required.""" @overload def __init__( self, *, - event_id: Optional[str] = None, + event_id: str, + event: dict[str, Any], + client_event_id: Optional[str] = None, + delegation_id: Optional[str] = None, ) -> None: ... @overload @@ -17630,35 +18714,67 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.INPUT_AUDIO_BUFFER_COMMIT # type: ignore + self.type = LiveServerEventType.RESPONSE_EVENT # type: ignore -class RealtimeClientEventOutputAudioBufferClear( - RealtimeClientEvent, discriminator="output_audio_buffer.clear" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """**WebRTC/SIP Only:** Emit to cut off the current audio response. This will trigger the server - to stop generating audio and emit a ``output_audio_buffer.cleared`` event. This event should be - preceded by a ``response.cancel`` client event to stop the generation of the current response. - `Learn more - `_. +class LiveServerEventLiveSessionClosed( + LiveServerEvent, discriminator="session.closed" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned after the Live session finishes finalizing, with the close reason, final session + snapshot, and cumulative audio usage. A connection closing without this event does not confirm + successful finalization. - :ivar event_id: The unique ID of the client event used for error handling. + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``output_audio_buffer.clear``. Required. - OUTPUT_AUDIO_BUFFER_CLEAR. - :vartype type: str or ~azure.ai.projects.models.OUTPUT_AUDIO_BUFFER_CLEAR + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``session.closed``. Required. SESSION_CLOSED. + :vartype type: str or ~azure.ai.projects.models.SESSION_CLOSED + :ivar reason: Why the Live session ended: ``close_requested`` for an application close or + hangup request, ``expired`` for the session duration limit, ``content`` for a safety filter, + ``remote_hangup`` for a graceful remote disconnect, or ``connection_lost`` for an unexpected + primary or upstream disconnection. Required. Is one of the following types: + Literal["close_requested"], Literal["expired"], Literal["content"], Literal["remote_hangup"], + Literal["connection_lost"] + :vartype reason: str or str or str or str or str + :ivar session: Required. + :vartype session: ~azure.ai.projects.models.VoiceAgentLiveSessionResource + :ivar usage: The final cumulative Live audio usage after session finalization. Required. + :vartype usage: ~azure.ai.projects.models.LiveSessionUsage """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the client event used for error handling.""" - type: Literal[RealtimeClientEventType.OUTPUT_AUDIO_BUFFER_CLEAR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``output_audio_buffer.clear``. Required. OUTPUT_AUDIO_BUFFER_CLEAR.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_CLOSED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.closed``. Required. SESSION_CLOSED.""" + reason: Literal["close_requested", "expired", "content", "remote_hangup", "connection_lost"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Why the Live session ended: ``close_requested`` for an application close or hangup request, + ``expired`` for the session duration limit, ``content`` for a safety filter, ``remote_hangup`` + for a graceful remote disconnect, or ``connection_lost`` for an unexpected primary or upstream + disconnection. Required. Is one of the following types: Literal[\"close_requested\"], + Literal[\"expired\"], Literal[\"content\"], Literal[\"remote_hangup\"], + Literal[\"connection_lost\"]""" + session: "_models.VoiceAgentLiveSessionResource" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + usage: "_models.LiveSessionUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The final cumulative Live audio usage after session finalization. Required.""" @overload def __init__( self, *, - event_id: Optional[str] = None, + event_id: str, + reason: Literal["close_requested", "expired", "content", "remote_hangup", "connection_lost"], + session: "_models.VoiceAgentLiveSessionResource", + usage: "_models.LiveSessionUsage", + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17670,40 +18786,51 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.OUTPUT_AUDIO_BUFFER_CLEAR # type: ignore + self.type = LiveServerEventType.SESSION_CLOSED # type: ignore -class RealtimeClientEventResponseCancel( - RealtimeClientEvent, discriminator="response.cancel" +class LiveServerEventLiveSessionStarted( + LiveServerEvent, discriminator="session.started" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Send this event to cancel an in-progress response. The server will respond with a - ``response.done`` event with a status of ``response.status=cancelled``. If there is no response - to cancel, the server will respond with an error. It's safe to call ``response.cancel`` even if - no response is in progress, an error will be returned the session will remain unaffected. + """Returned when a Live session has started. Contains the resolved session configuration, + including server defaults. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar type: The event type, always ``session.started``. Required. SESSION_STARTED. + :vartype type: str or ~azure.ai.projects.models.SESSION_STARTED + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``response.cancel``. Required. RESPONSE_CANCEL. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_CANCEL - :ivar response_id: A specific response ID to cancel - if not provided, will cancel an - in-progress response in the default conversation. - :vartype response_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar session: Required. + :vartype session: ~azure.ai.projects.models.VoiceAgentLiveSessionResource + :ivar conversation_id: Stored conversation ID when effective store is true. Use + protocols/voice/live/conversations; this ID differs from session.id. + :vartype conversation_id: str """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.RESPONSE_CANCEL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.cancel``. Required. RESPONSE_CANCEL.""" - response_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A specific response ID to cancel - if not provided, will cancel an in-progress response in the - default conversation.""" + type: Literal[LiveServerEventType.SESSION_STARTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.started``. Required. SESSION_STARTED.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + session: "_models.VoiceAgentLiveSessionResource" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Stored conversation ID when effective store is true. Use protocols/voice/live/conversations; + this ID differs from session.id.""" @overload def __init__( self, *, - event_id: Optional[str] = None, - response_id: Optional[str] = None, + event_id: str, + session: "_models.VoiceAgentLiveSessionResource", + client_event_id: Optional[str] = None, + conversation_id: Optional[str] = None, ) -> None: ... @overload @@ -17715,50 +18842,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.RESPONSE_CANCEL # type: ignore + self.type = LiveServerEventType.SESSION_STARTED # type: ignore -class RealtimeClientEventResponseCreate( - RealtimeClientEvent, discriminator="response.create" +class LiveServerEventLiveSessionUpdated( + LiveServerEvent, discriminator="session.updated" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """This event instructs the server to create a Response, which means triggering model inference. - When in Server VAD mode, the server will create Responses automatically. A Response will - include at least one Item, and may have two, in which case the second will be a function call. - These Items will be appended to the conversation history by default. The server will respond - with a ``response.created`` event, events for Items and content created, and finally a - ``response.done`` event to indicate the Response is complete. The ``response.create`` event - includes inference configuration like ``instructions`` and ``tools``. If these are set, they - will override the Session's configuration for this Response only. Responses can be created - out-of-band of the default Conversation, meaning that they can have arbitrary input, and it's - possible to disable writing the output to the Conversation. Only one Response can write to the - default Conversation at a time, but otherwise multiple Responses can be created in parallel. - The ``metadata`` field is a good way to disambiguate multiple simultaneous Responses. Clients - can set ``conversation`` to ``none`` to create a Response that does not write to the default - Conversation. Arbitrary input can be provided with the ``input`` field, which is an array - accepting raw Items and references to existing Items. + """Returned when a Live session update is accepted. Contains the resolved session configuration + after the update. - :ivar event_id: Optional client-generated ID used to identify this event. + :ivar type: The event type, always ``session.updated``. Required. SESSION_UPDATED. + :vartype type: str or ~azure.ai.projects.models.SESSION_UPDATED + :ivar event_id: The unique ID of the Live server event. Required. :vartype event_id: str - :ivar type: The event type, must be ``response.create``. Required. RESPONSE_CREATE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_CREATE - :ivar response: - :vartype response: ~azure.ai.projects.models.VoiceAgentResponseCreateParams + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar session: Required. + :vartype session: ~azure.ai.projects.models.VoiceAgentLiveSessionResource """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event.""" - type: Literal[RealtimeClientEventType.RESPONSE_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.create``. Required. RESPONSE_CREATE.""" - response: Optional["_models.VoiceAgentResponseCreateParams"] = rest_field( + type: Literal[LiveServerEventType.SESSION_UPDATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.updated``. Required. SESSION_UPDATED.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + session: "_models.VoiceAgentLiveSessionResource" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) + """Required.""" @overload def __init__( self, *, - event_id: Optional[str] = None, - response: Optional["_models.VoiceAgentResponseCreateParams"] = None, + event_id: str, + session: "_models.VoiceAgentLiveSessionResource", + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17770,33 +18891,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.RESPONSE_CREATE # type: ignore - + self.type = LiveServerEventType.SESSION_UPDATED # type: ignore -class RealtimeConversationItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A single item within a Realtime conversation. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - RealtimeConversationItemFunctionCall, RealtimeConversationItemFunctionCallOutput, - RealtimeMCPApprovalRequest, RealtimeMCPApprovalResponse, RealtimeMCPToolCall, - RealtimeMCPListTools, RealtimeConversationItemMessage +class LiveServerEventLiveSessionUsageUpdated( + LiveServerEvent, discriminator="session.usage.updated" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reports cumulative Live audio usage and, when available, the most recent context-window usage. + Delegated Responses token usage is reported separately in response.event events. - :ivar type: Required. Known values are: "function_call", "function_call_output", - "mcp_approval_response", "mcp_list_tools", "mcp_call", "mcp_approval_request", and "message". - :vartype type: str or ~azure.ai.projects.models.RealtimeConversationItemType + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar type: The event type, always ``session.usage.updated``. Required. SESSION_USAGE_UPDATED. + :vartype type: str or ~azure.ai.projects.models.SESSION_USAGE_UPDATED + :ivar usage: The cumulative Live audio usage so far. Required. + :vartype usage: ~azure.ai.projects.models.LiveSessionUsage + :ivar context_window: The latest measured Live context-window usage. Omitted when the context + limit is unknown. + :vartype context_window: ~azure.ai.projects.models.LiveContextWindowUsage """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"function_call\", \"function_call_output\", - \"mcp_approval_response\", \"mcp_list_tools\", \"mcp_call\", \"mcp_approval_request\", and - \"message\".""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + type: Literal[LiveServerEventType.SESSION_USAGE_UPDATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.usage.updated``. Required. SESSION_USAGE_UPDATED.""" + usage: "_models.LiveSessionUsage" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The cumulative Live audio usage so far. Required.""" + context_window: Optional["_models.LiveContextWindowUsage"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The latest measured Live context-window usage. Omitted when the context limit is unknown.""" @overload def __init__( self, *, - type: str, + event_id: str, + usage: "_models.LiveSessionUsage", + client_event_id: Optional[str] = None, + context_window: Optional["_models.LiveContextWindowUsage"] = None, ) -> None: ... @overload @@ -17808,71 +18946,52 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.SESSION_USAGE_UPDATED # type: ignore -class RealtimeConversationItemFunctionCall( - RealtimeConversationItem, discriminator="function_call" +class LiveServerEventLiveThinkingAppended( + LiveServerEvent, discriminator="session.thinking.appended" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime function call item. + """Returned when a session.thinking.append command is accepted into the Live session timeline. + Acknowledges the added reasoning context without guaranteeing any spoken output. - :ivar id: The unique ID of the item. This may be provided by the client or generated by the - server. - :vartype id: str - :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional - when creating a new item. Default value is "realtime.item". - :vartype object: str - :ivar type: The type of the item. Always ``function_call``. Required. FUNCTION_CALL. - :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL - :ivar status: The status of the item. Has no effect on the conversation. Is one of the - following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] - :vartype status: str or str or str - :ivar call_id: The ID of the function call. - :vartype call_id: str - :ivar name: The name of the function being called. Required. - :vartype name: str - :ivar arguments: The arguments of the function call. This is a JSON-encoded string representing - the arguments passed to the function, for example ``{"arg1": "value1", "arg2": 42}``. Required. - :vartype arguments: str - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar event_id: The unique ID of the Live server event. Required. + :vartype event_id: str + :ivar client_event_id: The event_id of the client command associated with this server event, + when supplied. + :vartype client_event_id: str + :ivar start_ms: The start of this event on the Live session timeline, in milliseconds from the + beginning of the session. Required. + :vartype start_ms: int + :ivar end_ms: The end of this event on the Live session timeline, in milliseconds from the + beginning of the session. For appended context, this can equal start_ms. Required. + :vartype end_ms: int + :ivar type: The event type, always ``session.thinking.appended``. Required. + SESSION_THINKING_APPENDED. + :vartype type: str or ~azure.ai.projects.models.SESSION_THINKING_APPENDED """ - id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the item. This may be provided by the client or generated by the server.""" - object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the API object being returned - always ``realtime.item``. Optional when creating - a new item. Default value is \"realtime.item\".""" - type: Literal[RealtimeConversationItemType.FUNCTION_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the item. Always ``function_call``. Required. FUNCTION_CALL.""" - status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The status of the item. Has no effect on the conversation. Is one of the following types: - Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" - call_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the function call.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function being called. Required.""" - arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The arguments of the function call. This is a JSON-encoded string representing the arguments - passed to the function, for example ``{\"arg1\": \"value1\", \"arg2\": 42}``. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live server event. Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command associated with this server event, when supplied.""" + start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The start of this event on the Live session timeline, in milliseconds from the beginning of the + session. Required.""" + end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The end of this event on the Live session timeline, in milliseconds from the beginning of the + session. For appended context, this can equal start_ms. Required.""" + type: Literal[LiveServerEventType.SESSION_THINKING_APPENDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, always ``session.thinking.appended``. Required. SESSION_THINKING_APPENDED.""" @overload def __init__( self, *, - name: str, - arguments: str, - id: Optional[str] = None, # pylint: disable=redefined-builtin - object: Optional[Literal["realtime.item"]] = None, - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, - call_id: Optional[str] = None, + event_id: str, + start_ms: int, + end_ms: int, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -17884,75 +19003,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.FUNCTION_CALL # type: ignore + self.type = LiveServerEventType.SESSION_THINKING_APPENDED # type: ignore -class RealtimeConversationItemFunctionCallOutput( - RealtimeConversationItem, discriminator="function_call_output" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Realtime function call output item. +class LiveServerEventLiveTransportAnswered( + LiveServerEvent, discriminator="transport.answered" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The outbound SIP provider leg answered and media is established. Delivered only to sideband + observers. - :ivar id: The unique ID of the item. This may be provided by the client or generated by the - server. - :vartype id: str - :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional - when creating a new item. Default value is "realtime.item". - :vartype object: str - :ivar type: The type of the item. Always ``function_call_output``. Required. - FUNCTION_CALL_OUTPUT. - :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL_OUTPUT - :ivar status: The status of the item. Has no effect on the conversation. Is one of the - following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] - :vartype status: str or str or str - :ivar call_id: The ID of the function call this output is for. Required. - :vartype call_id: str - :ivar output: The output of the function call, this is free text and can contain any - information or simply be empty. Required. - :vartype output: str - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str - :ivar name: The name of the function that was called. A Foundry extension: OpenAI's - function_call_output does not carry the function name, only ``call_id``. - :vartype name: str + :ivar event_id: Required. + :vartype event_id: str + :ivar session_id: The canonical Live session ID. Required. + :vartype session_id: str + :ivar type: Required. TRANSPORT_ANSWERED. + :vartype type: str or ~azure.ai.projects.models.TRANSPORT_ANSWERED """ - id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the item. This may be provided by the client or generated by the server.""" - object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the API object being returned - always ``realtime.item``. Optional when creating - a new item. Default value is \"realtime.item\".""" - type: Literal[RealtimeConversationItemType.FUNCTION_CALL_OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the item. Always ``function_call_output``. Required. FUNCTION_CALL_OUTPUT.""" - status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The status of the item. Has no effect on the conversation. Is one of the following types: - Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" - call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the function call this output is for. Required.""" - output: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The output of the function call, this is free text and can contain any information or simply be - empty. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function that was called. A Foundry extension: OpenAI's function_call_output - does not carry the function name, only ``call_id``.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + session_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The canonical Live session ID. Required.""" + type: Literal[LiveServerEventType.TRANSPORT_ANSWERED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. TRANSPORT_ANSWERED.""" @overload def __init__( self, *, - call_id: str, - output: str, - id: Optional[str] = None, # pylint: disable=redefined-builtin - object: Optional[Literal["realtime.item"]] = None, - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, - name: Optional[str] = None, + event_id: str, + session_id: str, ) -> None: ... @overload @@ -17964,35 +19044,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.FUNCTION_CALL_OUTPUT # type: ignore + self.type = LiveServerEventType.TRANSPORT_ANSWERED # type: ignore -class RealtimeConversationItemMessage( - RealtimeConversationItem, discriminator="message" +class LiveServerEventLiveTransportDtmfReceived( + LiveServerEvent, discriminator="transport.dtmf.received" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeConversationItemMessage. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - RealtimeConversationItemMessageAssistant, RealtimeConversationItemMessageSystem, - RealtimeConversationItemMessageUser + """A SIP DTMF keypress received from the caller. Delivered only to sideband observers. - :ivar role: Required. Known values are: "system", "user", and "assistant". - :vartype role: str or ~azure.ai.projects.models.RealtimeConversationItemMessageType - :ivar type: Required. MESSAGE. - :vartype type: str or ~azure.ai.projects.models.MESSAGE + :ivar type: Required. TRANSPORT_DTMF_RECEIVED. + :vartype type: str or ~azure.ai.projects.models.TRANSPORT_DTMF_RECEIVED + :ivar event_id: Required. + :vartype event_id: str + :ivar event: Required. + :vartype event: str """ - __mapping__: dict[str, _Model] = {} - role: str = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"system\", \"user\", and \"assistant\".""" - type: Literal[RealtimeConversationItemType.MESSAGE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. MESSAGE.""" + type: Literal[LiveServerEventType.TRANSPORT_DTMF_RECEIVED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. TRANSPORT_DTMF_RECEIVED.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + event: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - role: str, + event_id: str, + event: str, ) -> None: ... @overload @@ -18004,66 +19084,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.MESSAGE # type: ignore + self.type = LiveServerEventType.TRANSPORT_DTMF_RECEIVED # type: ignore -class RealtimeConversationItemMessageAssistant( - RealtimeConversationItemMessage, discriminator="assistant" +class LiveServerEventLiveTransportDtmfSent( + LiveServerEvent, discriminator="transport.dtmf.sent" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime assistant message item. + """A SIP DTMF keypress successfully sent to the SIP trunk. Delivered only to sideband observers; + this is not a client command. - :ivar id: The unique ID of the item. This may be provided by the client or generated by the - server. - :vartype id: str - :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional - when creating a new item. Default value is "realtime.item". - :vartype object: str - :ivar type: The type of the item. Always ``message``. Required. MESSAGE. - :vartype type: str or ~azure.ai.projects.models.MESSAGE - :ivar status: The status of the item. Has no effect on the conversation. Is one of the - following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] - :vartype status: str or str or str - :ivar role: The role of the message sender. Always ``assistant``. Required. ASSISTANT. - :vartype role: str or ~azure.ai.projects.models.ASSISTANT - :ivar content: The content of the message. Required. - :vartype content: - list[~azure.ai.projects.models.RealtimeConversationItemMessageAssistantContent] - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar type: Required. TRANSPORT_DTMF_SENT. + :vartype type: str or ~azure.ai.projects.models.TRANSPORT_DTMF_SENT + :ivar event_id: Required. + :vartype event_id: str + :ivar event: Required. + :vartype event: str + :ivar client_event_id: The event_id of the client command, when supplied. + :vartype client_event_id: str """ - id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the item. This may be provided by the client or generated by the server.""" - object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the API object being returned - always ``realtime.item``. Optional when creating - a new item. Default value is \"realtime.item\".""" - status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The status of the item. Has no effect on the conversation. Is one of the following types: - Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" - role: Literal[RealtimeConversationItemMessageType.ASSISTANT] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The role of the message sender. Always ``assistant``. Required. ASSISTANT.""" - content: list["_models.RealtimeConversationItemMessageAssistantContent"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The content of the message. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + type: Literal[LiveServerEventType.TRANSPORT_DTMF_SENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. TRANSPORT_DTMF_SENT.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + event: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + client_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event_id of the client command, when supplied.""" @overload def __init__( self, *, - type: Literal[RealtimeConversationItemType.MESSAGE], - content: list["_models.RealtimeConversationItemMessageAssistantContent"], - id: Optional[str] = None, # pylint: disable=redefined-builtin - object: Optional[Literal["realtime.item"]] = None, - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, + event_id: str, + event: str, + client_event_id: Optional[str] = None, ) -> None: ... @overload @@ -18075,40 +19130,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.role = RealtimeConversationItemMessageType.ASSISTANT # type: ignore + self.type = LiveServerEventType.TRANSPORT_DTMF_SENT # type: ignore -class RealtimeConversationItemMessageAssistantContent( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeConversationItemMessageAssistantContent. +class LiveServerEventLiveTransportFailed( + LiveServerEvent, discriminator="transport.failed" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An asynchronous outbound SIP setup failure. Delivered only to sideband observers. - :ivar type: Is either a Literal["output_text"] type or a Literal["output_audio"] type. - :vartype type: str or str - :ivar text: - :vartype text: str - :ivar audio: - :vartype audio: str - :ivar transcript: - :vartype transcript: str + :ivar event_id: Required. + :vartype event_id: str + :ivar session_id: The canonical Live session ID. Required. + :vartype session_id: str + :ivar type: Required. TRANSPORT_FAILED. + :vartype type: str or ~azure.ai.projects.models.TRANSPORT_FAILED + :ivar error: Required. + :vartype error: ~azure.ai.projects.models.LiveTransportCallError """ - type: Optional[Literal["output_text", "output_audio"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is either a Literal[\"output_text\"] type or a Literal[\"output_audio\"] type.""" - text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + session_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The canonical Live session ID. Required.""" + type: Literal[LiveServerEventType.TRANSPORT_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. TRANSPORT_FAILED.""" + error: "_models.LiveTransportCallError" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - type: Optional[Literal["output_text", "output_audio"]] = None, - text: Optional[str] = None, - audio: Optional[str] = None, - transcript: Optional[str] = None, + event_id: str, + session_id: str, + error: "_models.LiveTransportCallError", ) -> None: ... @overload @@ -18120,64 +19175,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveServerEventType.TRANSPORT_FAILED # type: ignore -class RealtimeConversationItemMessageSystem( - RealtimeConversationItemMessage, discriminator="system" +class LiveServerEventLiveTransportRinging( + LiveServerEvent, discriminator="transport.ringing" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime system message item. + """The outbound SIP provider leg is ringing or providing early media. Delivered only to sideband + observers. - :ivar id: The unique ID of the item. This may be provided by the client or generated by the - server. - :vartype id: str - :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional - when creating a new item. Default value is "realtime.item". - :vartype object: str - :ivar type: The type of the item. Always ``message``. Required. MESSAGE. - :vartype type: str or ~azure.ai.projects.models.MESSAGE - :ivar status: The status of the item. Has no effect on the conversation. Is one of the - following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] - :vartype status: str or str or str - :ivar role: The role of the message sender. Always ``system``. Required. SYSTEM. - :vartype role: str or ~azure.ai.projects.models.SYSTEM - :ivar content: The content of the message. Required. - :vartype content: list[~azure.ai.projects.models.RealtimeConversationItemMessageSystemContent] - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar event_id: Required. + :vartype event_id: str + :ivar session_id: The canonical Live session ID. Required. + :vartype session_id: str + :ivar type: Required. TRANSPORT_RINGING. + :vartype type: str or ~azure.ai.projects.models.TRANSPORT_RINGING """ - id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the item. This may be provided by the client or generated by the server.""" - object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the API object being returned - always ``realtime.item``. Optional when creating - a new item. Default value is \"realtime.item\".""" - status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The status of the item. Has no effect on the conversation. Is one of the following types: - Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" - role: Literal[RealtimeConversationItemMessageType.SYSTEM] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The role of the message sender. Always ``system``. Required. SYSTEM.""" - content: list["_models.RealtimeConversationItemMessageSystemContent"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The content of the message. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + session_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The canonical Live session ID. Required.""" + type: Literal[LiveServerEventType.TRANSPORT_RINGING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. TRANSPORT_RINGING.""" @overload def __init__( self, *, - type: Literal[RealtimeConversationItemType.MESSAGE], - content: list["_models.RealtimeConversationItemMessageSystemContent"], - id: Optional[str] = None, # pylint: disable=redefined-builtin - object: Optional[Literal["realtime.item"]] = None, - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, + event_id: str, + session_id: str, ) -> None: ... @overload @@ -18189,30 +19216,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.role = RealtimeConversationItemMessageType.SYSTEM # type: ignore + self.type = LiveServerEventType.TRANSPORT_RINGING # type: ignore -class RealtimeConversationItemMessageSystemContent( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeConversationItemMessageSystemContent. +class LiveSessionAudioFormatPCMAParam( + LiveAudioFormat, discriminator="audio/pcma" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Raw, mono G.711 A-law audio for a Live WebSocket connection. - :ivar type: Default value is "input_text". - :vartype type: str - :ivar text: - :vartype text: str + :ivar type: The audio encoding. Always ``audio/pcma``. Required. AUDIO_PCMA. + :vartype type: str or ~azure.ai.projects.models.AUDIO_PCMA + :ivar rate: Audio sample rate in hertz. G.711 audio uses 8000 Hz. Required. + :vartype rate: int """ - type: Optional[Literal["input_text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Default value is \"input_text\".""" - text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveAudioFormatType.AUDIO_PCMA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The audio encoding. Always ``audio/pcma``. Required. AUDIO_PCMA.""" + rate: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Audio sample rate in hertz. G.711 audio uses 8000 Hz. Required.""" @overload def __init__( self, *, - type: Optional[Literal["input_text"]] = None, - text: Optional[str] = None, + rate: int, ) -> None: ... @overload @@ -18224,64 +19251,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveAudioFormatType.AUDIO_PCMA # type: ignore -class RealtimeConversationItemMessageUser( - RealtimeConversationItemMessage, discriminator="user" +class LiveSessionAudioFormatPCMParam( + LiveAudioFormat, discriminator="audio/pcm" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime user message item. + """Raw, mono 16-bit little-endian PCM audio for a Live WebSocket connection. - :ivar id: The unique ID of the item. This may be provided by the client or generated by the - server. - :vartype id: str - :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional - when creating a new item. Default value is "realtime.item". - :vartype object: str - :ivar type: The type of the item. Always ``message``. Required. MESSAGE. - :vartype type: str or ~azure.ai.projects.models.MESSAGE - :ivar status: The status of the item. Has no effect on the conversation. Is one of the - following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] - :vartype status: str or str or str - :ivar role: The role of the message sender. Always ``user``. Required. USER. - :vartype role: str or ~azure.ai.projects.models.USER - :ivar content: The content of the message. Required. - :vartype content: list[~azure.ai.projects.models.RealtimeConversationItemMessageUserContent] - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar type: The audio encoding. Always ``audio/pcm``. Required. AUDIO_PCM. + :vartype type: str or ~azure.ai.projects.models.AUDIO_PCM + :ivar rate: Audio sample rate in hertz. Live WebSocket PCM audio supports 16000 or 24000 Hz. + Required. Is either a Literal[16000] type or a Literal[24000] type. + :vartype rate: int or int """ - id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the item. This may be provided by the client or generated by the server.""" - object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the API object being returned - always ``realtime.item``. Optional when creating - a new item. Default value is \"realtime.item\".""" - status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The status of the item. Has no effect on the conversation. Is one of the following types: - Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" - role: Literal[RealtimeConversationItemMessageType.USER] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The role of the message sender. Always ``user``. Required. USER.""" - content: list["_models.RealtimeConversationItemMessageUserContent"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The content of the message. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + type: Literal[LiveAudioFormatType.AUDIO_PCM] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The audio encoding. Always ``audio/pcm``. Required. AUDIO_PCM.""" + rate: Literal[16000, 24000] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Audio sample rate in hertz. Live WebSocket PCM audio supports 16000 or 24000 Hz. Required. Is + either a Literal[16000] type or a Literal[24000] type.""" @overload def __init__( self, *, - type: Literal[RealtimeConversationItemType.MESSAGE], - content: list["_models.RealtimeConversationItemMessageUserContent"], - id: Optional[str] = None, # pylint: disable=redefined-builtin - object: Optional[Literal["realtime.item"]] = None, - status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, + rate: Literal[16000, 24000], ) -> None: ... @overload @@ -18293,53 +19288,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.role = RealtimeConversationItemMessageType.USER # type: ignore + self.type = LiveAudioFormatType.AUDIO_PCM # type: ignore -class RealtimeConversationItemMessageUserContent( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeConversationItemMessageUserContent. +class LiveSessionAudioFormatPCMUParam( + LiveAudioFormat, discriminator="audio/pcmu" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Raw, mono G.711 μ-law audio for a Live WebSocket connection. - :ivar type: Is one of the following types: Literal["input_text"], Literal["input_audio"], - Literal["input_image"] - :vartype type: str or str or str - :ivar text: - :vartype text: str - :ivar audio: - :vartype audio: str - :ivar image_url: - :vartype image_url: str - :ivar detail: Is one of the following types: Literal["auto"], Literal["low"], Literal["high"] - :vartype detail: str or str or str - :ivar transcript: - :vartype transcript: str + :ivar type: The audio encoding. Always ``audio/pcmu``. Required. AUDIO_PCMU. + :vartype type: str or ~azure.ai.projects.models.AUDIO_PCMU + :ivar rate: Audio sample rate in hertz. G.711 audio uses 8000 Hz. Required. + :vartype rate: int """ - type: Optional[Literal["input_text", "input_audio", "input_image"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is one of the following types: Literal[\"input_text\"], Literal[\"input_audio\"], - Literal[\"input_image\"]""" - text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - image_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - detail: Optional[Literal["auto", "low", "high"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is one of the following types: Literal[\"auto\"], Literal[\"low\"], Literal[\"high\"]""" - transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveAudioFormatType.AUDIO_PCMU] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The audio encoding. Always ``audio/pcmu``. Required. AUDIO_PCMU.""" + rate: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Audio sample rate in hertz. G.711 audio uses 8000 Hz. Required.""" @overload def __init__( self, *, - type: Optional[Literal["input_text", "input_audio", "input_image"]] = None, - text: Optional[str] = None, - audio: Optional[str] = None, - image_url: Optional[str] = None, - detail: Optional[Literal["auto", "low", "high"]] = None, - transcript: Optional[str] = None, + rate: int, ) -> None: ... @overload @@ -18351,42 +19323,82 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveAudioFormatType.AUDIO_PCMU # type: ignore -class RealtimeFunctionTool(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Function tool. +class LiveSessionCreateParams(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Initial configuration for a Live session, including its model, conversation instructions, + audio, and delegated task handling. - :ivar type: The type of the tool, i.e. ``function``. Default value is "function". - :vartype type: str - :ivar name: The name of the function. - :vartype name: str - :ivar description: The description of the function, including guidance on when and how to call - it, and guidance about what to tell the user when calling (if anything). - :vartype description: str - :ivar parameters: Parameters of the function in JSON Schema. - :vartype parameters: ~azure.ai.projects.models.RealtimeFunctionToolParameters + :ivar model: Required. "gpt-live-1" + :vartype model: str or ~azure.ai.projects.models.ModelIdsLive + :ivar instructions: + :vartype instructions: str + :ivar input: Ordered text-only history supplied before startup. Supports developer, user, and + assistant messages with one text part each; at most 128 messages and a configured + rendered-token limit (8,192 by default). + :vartype input: list[~azure.ai.projects.models.LiveInitialItem] + :ivar audio: Startup audio configuration. Only primary WebSockets accept audio.format; WebRTC + and SIP negotiate their media format. Voice and format are immutable after startup. + :vartype audio: ~azure.ai.projects.models.LiveInitialSessionAudioParam + :ivar delegation: + :vartype delegation: ~azure.ai.projects.models.LiveSessionCreateParamsDelegation + :ivar triggers: At most one Decisions trigger per transcript event type. Triggers run + independently of delegation. On update, omit triggers to keep the current configuration, send a + list to replace it, or send an empty list to disable triggers. + :vartype triggers: list[~azure.ai.projects.models.LiveDecisionTriggerInputParam] + :ivar store: Whether to store the session for later forking and recording download. Defaults to + false for new sessions. + :vartype store: bool + :ivar client: Startup-only capabilities for an untrusted frontend attached to a unified WebRTC + session. Trusted sideband connections are unaffected. + :vartype client: ~azure.ai.projects.models.LiveClientConfigParam """ - type: Optional[Literal["function"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The type of the tool, i.e. ``function``. Default value is \"function\".""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The description of the function, including guidance on when and how to call it, and guidance - about what to tell the user when calling (if anything).""" - parameters: Optional["_models.RealtimeFunctionToolParameters"] = rest_field( + model: Union[str, "_models.ModelIdsLive"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. \"gpt-live-1\"""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input: Optional[list["_models.LiveInitialItem"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Parameters of the function in JSON Schema.""" + """Ordered text-only history supplied before startup. Supports developer, user, and assistant + messages with one text part each; at most 128 messages and a configured rendered-token limit + (8,192 by default).""" + audio: Optional["_models.LiveInitialSessionAudioParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Startup audio configuration. Only primary WebSockets accept audio.format; WebRTC and SIP + negotiate their media format. Voice and format are immutable after startup.""" + delegation: Optional["_models.LiveSessionCreateParamsDelegation"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + triggers: Optional[list["_models.LiveDecisionTriggerInputParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """At most one Decisions trigger per transcript event type. Triggers run independently of + delegation. On update, omit triggers to keep the current configuration, send a list to replace + it, or send an empty list to disable triggers.""" + store: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to store the session for later forking and recording download. Defaults to false for + new sessions.""" + client: Optional["_models.LiveClientConfigParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Startup-only capabilities for an untrusted frontend attached to a unified WebRTC session. + Trusted sideband connections are unaffected.""" @overload def __init__( self, *, - type: Optional[Literal["function"]] = None, - name: Optional[str] = None, - description: Optional[str] = None, - parameters: Optional["_models.RealtimeFunctionToolParameters"] = None, + model: Union[str, "_models.ModelIdsLive"], + instructions: Optional[str] = None, + input: Optional[list["_models.LiveInitialItem"]] = None, + audio: Optional["_models.LiveInitialSessionAudioParam"] = None, + delegation: Optional["_models.LiveSessionCreateParamsDelegation"] = None, + triggers: Optional[list["_models.LiveDecisionTriggerInputParam"]] = None, + store: Optional[bool] = None, + client: Optional["_models.LiveClientConfigParam"] = None, ) -> None: ... @overload @@ -18400,55 +19412,28 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RealtimeFunctionToolParameters(_Model): - """RealtimeFunctionToolParameters.""" - +class LiveSessionCreateParamsDelegation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Who handles tasks delegated by the Live model. Omitted or null selects your application; use + ``responses`` or ``decisions`` to delegate to the corresponding API. -class RealtimeMCPApprovalRequest( - RealtimeConversationItem, discriminator="mcp_approval_request" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP approval request. + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + LiveSessionCreateParamsDelegationLiveClientDelegationParam, + LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam, + LiveSessionCreateParamsDelegationLiveResponsesDelegationParam - :ivar type: The type of the item. Always ``mcp_approval_request``. Required. - MCP_APPROVAL_REQUEST. - :vartype type: str or ~azure.ai.projects.models.MCP_APPROVAL_REQUEST - :ivar id: The unique ID of the approval request. Required. - :vartype id: str - :ivar server_label: The label of the MCP server making the request. Required. - :vartype server_label: str - :ivar name: The name of the tool to run. Required. - :vartype name: str - :ivar arguments: A JSON string of arguments for the tool. Required. - :vartype arguments: str - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar type: Required. Known values are: "client", "responses", and "decisions". + :vartype type: str or ~azure.ai.projects.models.LiveSessionCreateParamsDelegationType """ - type: Literal[RealtimeConversationItemType.MCP_APPROVAL_REQUEST] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the item. Always ``mcp_approval_request``. Required. MCP_APPROVAL_REQUEST.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the approval request. Required.""" - server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The label of the MCP server making the request. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the tool to run. Required.""" - arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A JSON string of arguments for the tool. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"client\", \"responses\", and \"decisions\".""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - server_label: str, - name: str, - arguments: str, + type: str, ) -> None: ... @overload @@ -18460,53 +19445,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.MCP_APPROVAL_REQUEST # type: ignore -class RealtimeMCPApprovalResponse( - RealtimeConversationItem, discriminator="mcp_approval_response" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP approval response. +class LiveSessionCreateParamsDelegationLiveClientDelegationParam( + LiveSessionCreateParamsDelegation, discriminator="client" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Delegate tasks to your application. The Live session emits delegation events that your backend + handles. - :ivar type: The type of the item. Always ``mcp_approval_response``. Required. - MCP_APPROVAL_RESPONSE. - :vartype type: str or ~azure.ai.projects.models.MCP_APPROVAL_RESPONSE - :ivar id: The unique ID of the approval response. Required. - :vartype id: str - :ivar approval_request_id: The ID of the approval request being answered. Required. - :vartype approval_request_id: str - :ivar approve: Whether the request was approved. Required. - :vartype approve: bool - :ivar reason: - :vartype reason: str - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: The delegation owner. Always ``client`` for tasks handled by your application. + Required. CLIENT. + :vartype type: str or ~azure.ai.projects.models.CLIENT """ - type: Literal[RealtimeConversationItemType.MCP_APPROVAL_RESPONSE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the item. Always ``mcp_approval_response``. Required. MCP_APPROVAL_RESPONSE.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the approval response. Required.""" - approval_request_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the approval request being answered. Required.""" - approve: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the request was approved. Required.""" - reason: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + type: Literal[LiveSessionCreateParamsDelegationType.CLIENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The delegation owner. Always ``client`` for tasks handled by your application. Required. + CLIENT.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - approval_request_id: str, - approve: bool, - reason: Optional[str] = None, + acknowledgement_delay_ms: Optional[int] = None, ) -> None: ... @overload @@ -18518,29 +19491,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.MCP_APPROVAL_RESPONSE # type: ignore + self.type = LiveSessionCreateParamsDelegationType.CLIENT # type: ignore -class RealtimeMCPError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeMCPError. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - RealtimeMCPHTTPError, RealtimeMCPProtocolError, RealtimeMCPToolExecutionError +class LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam( + LiveSessionCreateParamsDelegation, discriminator="decisions" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """LiveSessionCreateParamsDelegationLiveDecisionsDelegationParam. - :ivar type: Required. Known values are: "protocol_error", "tool_execution_error", and - "http_error". - :vartype type: str or ~azure.ai.projects.models.RealtimeMcpErrorType + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400. Updates apply to subsequent delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: Required. DECISIONS. + :vartype type: str or ~azure.ai.projects.models.DECISIONS + :ivar decisions: Required. + :vartype decisions: ~azure.ai.projects.models.LiveDecisionsSettingsInputParam """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"protocol_error\", \"tool_execution_error\", and \"http_error\".""" + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400. + Updates apply to subsequent delegations.""" + type: Literal[LiveSessionCreateParamsDelegationType.DECISIONS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DECISIONS.""" + decisions: "_models.LiveDecisionsSettingsInputParam" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" @overload def __init__( self, *, - type: str, + decisions: "_models.LiveDecisionsSettingsInputParam", + acknowledgement_delay_ms: Optional[int] = None, ) -> None: ... @overload @@ -18552,34 +19539,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = LiveSessionCreateParamsDelegationType.DECISIONS # type: ignore -class RealtimeMCPHTTPError( - RealtimeMCPError, discriminator="http_error" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP HTTP error. - - :ivar type: Required. HTTP_ERROR. - :vartype type: str or ~azure.ai.projects.models.HTTP_ERROR - :ivar code: Required. - :vartype code: int - :ivar message: Required. - :vartype message: str - """ - - type: Literal[RealtimeMcpErrorType.HTTP_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. HTTP_ERROR.""" - code: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" +class LiveSessionCreateParamsDelegationLiveResponsesDelegationParam( + LiveSessionCreateParamsDelegation, discriminator="responses" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Delegate tasks to a Responses model managed by the Live session. + + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: The delegation owner. Always ``responses`` for tasks handled by the Responses API. + Required. RESPONSES. + :vartype type: str or ~azure.ai.projects.models.RESPONSES + :ivar responses: Backend model, prompt, and tools used when the Live session delegates a task + to Responses. Required. + :vartype responses: ~azure.ai.projects.models.LiveResponsesDelegationSettingsInputParam + """ + + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + type: Literal[LiveSessionCreateParamsDelegationType.RESPONSES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The delegation owner. Always ``responses`` for tasks handled by the Responses API. Required. + RESPONSES.""" + responses: "_models.LiveResponsesDelegationSettingsInputParam" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Backend model, prompt, and tools used when the Live session delegates a task to Responses. + Required.""" @overload def __init__( self, *, - code: int, - message: str, + responses: "_models.LiveResponsesDelegationSettingsInputParam", + acknowledgement_delay_ms: Optional[int] = None, ) -> None: ... @overload @@ -18591,48 +19594,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeMcpErrorType.HTTP_ERROR # type: ignore + self.type = LiveSessionCreateParamsDelegationType.RESPONSES # type: ignore -class RealtimeMCPListTools( - RealtimeConversationItem, discriminator="mcp_list_tools" +class LiveSessionStartEvent( + LiveClientEvent, discriminator="session.start" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP list tools. + """Start a Live session on a primary WebSocket. Send this event before other commands and wait for + ``session.started``. - :ivar type: The type of the item. Always ``mcp_list_tools``. Required. MCP_LIST_TOOLS. - :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS - :ivar id: The unique ID of the list. - :vartype id: str - :ivar server_label: The label of the MCP server. Required. - :vartype server_label: str - :ivar tools: The tools available on the server. Required. - :vartype tools: list[~azure.ai.projects.models.MCPListToolsTool] - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar event_id: + :vartype event_id: str + :ivar type: The Live client event type. Always ``session.start``. Required. SESSION_START. + :vartype type: str or ~azure.ai.projects.models.SESSION_START + :ivar session: Initial configuration for a primary WebSocket. Send session.start first and wait + for session.started before application commands. WebRTC creation already starts the session; do + not send this event again on its data channel. Required. + :vartype session: ~azure.ai.projects.models.LiveSessionCreateParams """ - type: Literal[RealtimeConversationItemType.MCP_LIST_TOOLS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the item. Always ``mcp_list_tools``. Required. MCP_LIST_TOOLS.""" - id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the list.""" - server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The label of the MCP server. Required.""" - tools: list["_models.MCPListToolsTool"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The tools available on the server. Required.""" - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal[LiveClientEventType.SESSION_START] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Live client event type. Always ``session.start``. Required. SESSION_START.""" + session: "_models.LiveSessionCreateParams" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Initial configuration for a primary WebSocket. Send session.start first and wait for + session.started before application commands. WebRTC creation already starts the session; do not + send this event again on its data channel. Required.""" @overload def __init__( self, *, - server_label: str, - tools: list["_models.MCPListToolsTool"], - id: Optional[str] = None, # pylint: disable=redefined-builtin + session: "_models.LiveSessionCreateParams", + event_id: Optional[str] = None, ) -> None: ... @overload @@ -18644,35 +19638,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.MCP_LIST_TOOLS # type: ignore + self.type = LiveClientEventType.SESSION_START # type: ignore -class RealtimeMCPProtocolError( - RealtimeMCPError, discriminator="protocol_error" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP protocol error. +class LiveSessionUpdateParams(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Changes to an active Live session's delegation settings and transcript triggers. - :ivar type: Required. PROTOCOL_ERROR. - :vartype type: str or ~azure.ai.projects.models.PROTOCOL_ERROR - :ivar code: Required. - :vartype code: int - :ivar message: Required. - :vartype message: str + :ivar delegation: + :vartype delegation: ~azure.ai.projects.models.LiveSessionUpdateParamsDelegation + :ivar triggers: At most one Decisions trigger per transcript event type. Triggers run + independently of delegation. On update, omit triggers to keep the current configuration, send a + list to replace it, or send an empty list to disable triggers. + :vartype triggers: list[~azure.ai.projects.models.LiveDecisionTriggerInputParam] """ - type: Literal[RealtimeMcpErrorType.PROTOCOL_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. PROTOCOL_ERROR.""" - code: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + delegation: Optional["_models.LiveSessionUpdateParamsDelegation"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + triggers: Optional[list["_models.LiveDecisionTriggerInputParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """At most one Decisions trigger per transcript event type. Triggers run independently of + delegation. On update, omit triggers to keep the current configuration, send a list to replace + it, or send an empty list to disable triggers.""" @overload def __init__( self, *, - code: int, - message: str, + delegation: Optional["_models.LiveSessionUpdateParamsDelegation"] = None, + triggers: Optional[list["_models.LiveDecisionTriggerInputParam"]] = None, ) -> None: ... @overload @@ -18684,65 +19679,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeMcpErrorType.PROTOCOL_ERROR # type: ignore -class RealtimeMCPToolCall( - RealtimeConversationItem, discriminator="mcp_call" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP tool call. +class LiveSessionUpdateParamsDelegationLiveClientDelegationParam( + LiveSessionUpdateParamsDelegation, discriminator="client" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Delegate tasks to your application. The Live session emits delegation events that your backend + handles. - :ivar type: The type of the item. Always ``mcp_call``. Required. MCP_CALL. - :vartype type: str or ~azure.ai.projects.models.MCP_CALL - :ivar id: The unique ID of the tool call. Required. - :vartype id: str - :ivar server_label: The label of the MCP server running the tool. Required. - :vartype server_label: str - :ivar name: The name of the tool that was run. Required. - :vartype name: str - :ivar arguments: A JSON string of the arguments passed to the tool. Required. - :vartype arguments: str - :ivar approval_request_id: - :vartype approval_request_id: str - :ivar output: - :vartype output: str - :ivar error: - :vartype error: ~azure.ai.projects.models.RealtimeMCPError - :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. - :vartype created_at: ~datetime.datetime - :ivar response_id: The id of the response that produced this item, when applicable. - :vartype response_id: str + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: The delegation owner. Always ``client`` for tasks handled by your application. + Required. CLIENT. + :vartype type: str or ~azure.ai.projects.models.CLIENT """ - type: Literal[RealtimeConversationItemType.MCP_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the item. Always ``mcp_call``. Required. MCP_CALL.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the tool call. Required.""" - server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The label of the MCP server running the tool. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the tool that was run. Required.""" - arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A JSON string of the arguments passed to the tool. Required.""" - approval_request_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - output: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - error: Optional["_models.RealtimeMCPError"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The Unix timestamp (in seconds) for when the item was persisted.""" - response_id: Optional[str] = rest_field(visibility=["read"]) - """The id of the response that produced this item, when applicable.""" + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + type: Literal[LiveSessionUpdateParamsDelegationType.CLIENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The delegation owner. Always ``client`` for tasks handled by your application. Required. + CLIENT.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - server_label: str, - name: str, - arguments: str, - approval_request_id: Optional[str] = None, - output: Optional[str] = None, - error: Optional["_models.RealtimeMCPError"] = None, + acknowledgement_delay_ms: Optional[int] = None, ) -> None: ... @overload @@ -18754,30 +19725,27 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeConversationItemType.MCP_CALL # type: ignore + self.type = LiveSessionUpdateParamsDelegationType.CLIENT # type: ignore -class RealtimeMCPToolExecutionError( - RealtimeMCPError, discriminator="tool_execution_error" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime MCP tool execution error. +class LiveSessionUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Cumulative audio duration for a Live session. Values are totals for the session, not increments + to sum across usage events. - :ivar type: Required. TOOL_EXECUTION_ERROR. - :vartype type: str or ~azure.ai.projects.models.TOOL_EXECUTION_ERROR - :ivar message: Required. - :vartype message: str + :ivar seconds: The cumulative Live audio duration in seconds. Do not sum this value across + usage events. Required. + :vartype seconds: float """ - type: Literal[RealtimeMcpErrorType.TOOL_EXECUTION_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. TOOL_EXECUTION_ERROR.""" - message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + seconds: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The cumulative Live audio duration in seconds. Do not sum this value across usage events. + Required.""" @overload def __init__( self, *, - message: str, + seconds: float, ) -> None: ... @overload @@ -18789,26 +19757,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeMcpErrorType.TOOL_EXECUTION_ERROR # type: ignore -class RealtimeReasoning(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Realtime reasoning configuration. +class LiveSkillReferenceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveSkillReferenceParam. - :ivar effort: Known values are: "minimal", "low", "medium", "high", and "xhigh". - :vartype effort: str or ~azure.ai.projects.models.RealtimeReasoningEffort + :ivar type: References a skill created with the /v1/skills endpoint. Required. Default value is + "skill_reference". + :vartype type: str + :ivar skill_id: The ID of the referenced skill. Required. + :vartype skill_id: str + :ivar version: + :vartype version: str """ - effort: Optional[Union[str, "_models.RealtimeReasoningEffort"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Known values are: \"minimal\", \"low\", \"medium\", \"high\", and \"xhigh\".""" + type: Literal["skill_reference"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """References a skill created with the /v1/skills endpoint. Required. Default value is + \"skill_reference\".""" + skill_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the referenced skill. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - effort: Optional[Union[str, "_models.RealtimeReasoningEffort"]] = None, + skill_id: str, + version: Optional[str] = None, ) -> None: ... @overload @@ -18820,167 +19795,74 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["skill_reference"] = "skill_reference" -class RealtimeResponseStatusDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeResponseStatusDetails. +class LiveSpecificApplyPatchParam(_Model): # pylint: disable=docstring-missing-param + """Specific apply patch tool choice. - :ivar type: Is one of the following types: Literal["completed"], Literal["cancelled"], - Literal["failed"], Literal["incomplete"] - :vartype type: str or str or str or str - :ivar reason: Is one of the following types: Literal["turn_detected"], - Literal["client_cancelled"], Literal["max_output_tokens"], Literal["content_filter"] - :vartype reason: str or str or str or str - :ivar error: - :vartype error: ~azure.ai.projects.models.RealtimeResponseStatusDetailsError + :ivar type: The tool to call. Always ``apply_patch``. Required. Default value is "apply_patch". + :vartype type: str """ - type: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is one of the following types: Literal[\"completed\"], Literal[\"cancelled\"], - Literal[\"failed\"], Literal[\"incomplete\"]""" - reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is one of the following types: Literal[\"turn_detected\"], Literal[\"client_cancelled\"], - Literal[\"max_output_tokens\"], Literal[\"content_filter\"]""" - error: Optional["_models.RealtimeResponseStatusDetailsError"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - - @overload - def __init__( - self, - *, - type: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = None, - reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = None, - error: Optional["_models.RealtimeResponseStatusDetailsError"] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ + type: Literal["apply_patch"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``apply_patch``. Required. Default value is \"apply_patch\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["apply_patch"] = "apply_patch" -class RealtimeResponseStatusDetailsError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeResponseStatusDetailsError. +class LiveSpecificCodeInterpreterParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificCodeInterpreterParam. - :ivar type: + :ivar type: The tool to call. Always ``code_interpreter``. Required. Default value is + "code_interpreter". :vartype type: str - :ivar code: - :vartype code: str """ - type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - - @overload - def __init__( - self, - *, - type: Optional[str] = None, - code: 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] - """ + type: Literal["code_interpreter"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``code_interpreter``. Required. Default value is \"code_interpreter\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["code_interpreter"] = "code_interpreter" -class RealtimeResponseUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeResponseUsage. +class LiveSpecificComputerParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificComputerParam. - :ivar total_tokens: - :vartype total_tokens: int - :ivar input_tokens: - :vartype input_tokens: int - :ivar output_tokens: - :vartype output_tokens: int - :ivar input_token_details: - :vartype input_token_details: ~azure.ai.projects.models.RealtimeResponseUsageInputTokenDetails - :ivar output_token_details: - :vartype output_token_details: - ~azure.ai.projects.models.RealtimeResponseUsageOutputTokenDetails + :ivar type: The tool to call. Always ``computer``. Required. Default value is "computer". + :vartype type: str """ - total_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - input_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - output_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - input_token_details: Optional["_models.RealtimeResponseUsageInputTokenDetails"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - output_token_details: Optional["_models.RealtimeResponseUsageOutputTokenDetails"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - - @overload - def __init__( - self, - *, - total_tokens: Optional[int] = None, - input_tokens: Optional[int] = None, - output_tokens: Optional[int] = None, - input_token_details: Optional["_models.RealtimeResponseUsageInputTokenDetails"] = None, - output_token_details: Optional["_models.RealtimeResponseUsageOutputTokenDetails"] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ + type: Literal["computer"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``computer``. Required. Default value is \"computer\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["computer"] = "computer" -class RealtimeResponseUsageInputTokenDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeResponseUsageInputTokenDetails. +class LiveSpecificCustomToolParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveSpecificCustomToolParam. - :ivar cached_tokens: - :vartype cached_tokens: int - :ivar text_tokens: - :vartype text_tokens: int - :ivar image_tokens: - :vartype image_tokens: int - :ivar audio_tokens: - :vartype audio_tokens: int - :ivar cached_tokens_details: - :vartype cached_tokens_details: - ~azure.ai.projects.models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails + :ivar type: The tool to call. Always ``custom``. Required. Default value is "custom". + :vartype type: str + :ivar name: The name of the custom tool to call. Required. + :vartype name: str """ - cached_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - image_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - cached_tokens_details: Optional["_models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) + type: Literal["custom"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``custom``. Required. Default value is \"custom\".""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the custom tool to call. Required.""" @overload def __init__( self, *, - cached_tokens: Optional[int] = None, - text_tokens: Optional[int] = None, - image_tokens: Optional[int] = None, - audio_tokens: Optional[int] = None, - cached_tokens_details: Optional["_models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails"] = None, + name: str, ) -> None: ... @overload @@ -18992,234 +19874,148 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["custom"] = "custom" -class RealtimeResponseUsageInputTokenDetailsCachedTokensDetails( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeResponseUsageInputTokenDetailsCachedTokensDetails. +class LiveSpecificFileSearchParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificFileSearchParam. - :ivar text_tokens: - :vartype text_tokens: int - :ivar image_tokens: - :vartype image_tokens: int - :ivar audio_tokens: - :vartype audio_tokens: int + :ivar type: The tool to call. Always ``file_search``. Required. Default value is "file_search". + :vartype type: str """ - text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - image_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - - @overload - def __init__( - self, - *, - text_tokens: Optional[int] = None, - image_tokens: Optional[int] = None, - audio_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] - """ + type: Literal["file_search"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``file_search``. Required. Default value is \"file_search\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["file_search"] = "file_search" -class RealtimeResponseUsageOutputTokenDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeResponseUsageOutputTokenDetails. +class LiveSpecificFunctionShellParam(_Model): # pylint: disable=docstring-missing-param + """Specific shell tool choice. - :ivar text_tokens: - :vartype text_tokens: int - :ivar audio_tokens: - :vartype audio_tokens: int + :ivar type: The tool to call. Always ``shell``. Required. Default value is "shell". + :vartype type: str """ - text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal["shell"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``shell``. Required. Default value is \"shell\".""" - @overload - def __init__( - self, - *, - text_tokens: Optional[int] = None, - audio_tokens: Optional[int] = None, - ) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["shell"] = "shell" - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ + +class LiveSpecificImageGenParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificImageGenParam. + + :ivar type: The tool to call. Always ``image_generation``. Required. Default value is + "image_generation". + :vartype type: str + """ + + type: Literal["image_generation"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``image_generation``. Required. Default value is \"image_generation\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["image_generation"] = "image_generation" -class RealtimeServerEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A realtime server event. +class LiveSpecificProgrammaticToolCallingParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificProgrammaticToolCallingParam. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - RealtimeServerEventConversationItemAdded, RealtimeServerEventConversationItemCreated, - RealtimeServerEventConversationItemDeleted, RealtimeServerEventConversationItemDone, - RealtimeServerEventConversationItemInputAudioTranscriptionCompleted, - RealtimeServerEventConversationItemInputAudioTranscriptionDelta, - RealtimeServerEventConversationItemInputAudioTranscriptionFailed, - RealtimeServerEventConversationItemInputAudioTranscriptionSegment, - RealtimeServerEventConversationItemRetrieved, RealtimeServerEventConversationItemTruncated, - RealtimeServerEventInputAudioBufferCleared, RealtimeServerEventInputAudioBufferCommitted, - RealtimeServerEventInputAudioBufferSpeechStarted, - RealtimeServerEventInputAudioBufferSpeechStopped, - RealtimeServerEventInputAudioBufferTimeoutTriggered, RealtimeServerEventMCPListToolsCompleted, - RealtimeServerEventMCPListToolsFailed, RealtimeServerEventMCPListToolsInProgress, - RealtimeServerEventOutputAudioBufferCleared, RealtimeServerEventRateLimitsUpdated, - VoiceAgentServerEventResponseAnimationBlendshapesDelta, - VoiceAgentServerEventResponseAnimationBlendshapesDone, - VoiceAgentServerEventResponseAnimationVisemeDelta, - VoiceAgentServerEventResponseAnimationVisemeDone, - VoiceAgentServerEventResponseAudioTimestampDelta, - VoiceAgentServerEventResponseAudioTimestampDone, RealtimeServerEventResponseContentPartAdded, - RealtimeServerEventResponseContentPartDone, RealtimeServerEventResponseCreated, - RealtimeServerEventResponseDone, RealtimeServerEventResponseFunctionCallArgumentsDelta, - RealtimeServerEventResponseFunctionCallArgumentsDone, - RealtimeServerEventResponseMCPCallCompleted, RealtimeServerEventResponseMCPCallFailed, - RealtimeServerEventResponseMCPCallInProgress, RealtimeServerEventResponseMCPCallArgumentsDelta, - RealtimeServerEventResponseMCPCallArgumentsDone, RealtimeServerEventResponseAudioDelta, - RealtimeServerEventResponseAudioDone, RealtimeServerEventResponseAudioTranscriptDelta, - RealtimeServerEventResponseAudioTranscriptDone, RealtimeServerEventResponseOutputItemAdded, - RealtimeServerEventResponseOutputItemDone, RealtimeServerEventResponseTextDelta, - RealtimeServerEventResponseTextDone, VoiceAgentServerEventResponseVideoDelta, - VoiceAgentServerEventRtcCallError, VoiceAgentServerEventRtcCallSdpCreated, - VoiceAgentServerEventSessionAvatarConnecting, VoiceAgentServerEventSessionAvatarSwitchToIdle, - VoiceAgentServerEventSessionAvatarSwitchToSpeaking, RealtimeServerEventSessionCreated, - VoiceAgentServerEventSessionSubagentAborted, VoiceAgentServerEventSessionSubagentCompleted, - VoiceAgentServerEventSessionSubagentStarted, RealtimeServerEventSessionUpdated, - VoiceAgentServerEventWarning + :ivar type: The tool to call. Always ``programmatic_tool_calling``. Required. Default value is + "programmatic_tool_calling". + :vartype type: str + """ - :ivar type: Required. Known values are: "conversation.created", "conversation.item.created", - "conversation.item.deleted", "conversation.item.input_audio_transcription.completed", - "conversation.item.input_audio_transcription.delta", - "conversation.item.input_audio_transcription.failed", "conversation.item.retrieved", - "conversation.item.truncated", "error", "input_audio_buffer.cleared", - "input_audio_buffer.committed", "input_audio_buffer.dtmf_event_received", - "input_audio_buffer.speech_started", "input_audio_buffer.speech_stopped", - "rate_limits.updated", "response.output_audio.delta", "response.output_audio.done", - "response.output_audio_transcript.delta", "response.output_audio_transcript.done", - "response.content_part.added", "response.content_part.done", "response.created", - "response.done", "response.function_call_arguments.delta", - "response.function_call_arguments.done", "response.output_item.added", - "response.output_item.done", "response.output_text.delta", "response.output_text.done", - "session.created", "session.updated", "output_audio_buffer.started", - "output_audio_buffer.stopped", "output_audio_buffer.cleared", "conversation.item.added", - "conversation.item.done", "input_audio_buffer.timeout_triggered", - "conversation.item.input_audio_transcription.segment", "mcp_list_tools.in_progress", - "mcp_list_tools.completed", "mcp_list_tools.failed", "response.mcp_call_arguments.delta", - "response.mcp_call_arguments.done", "response.mcp_call.in_progress", - "response.mcp_call.completed", "response.mcp_call.failed", "warning", - "session.subagent.started", "session.subagent.completed", "session.subagent.aborted", - "session.avatar.connecting", "session.avatar.switch_to_speaking", - "session.avatar.switch_to_idle", "rtc.call.sdp.created", "rtc.call.error", - "response.audio_timestamp.delta", "response.audio_timestamp.done", - "response.animation_blendshapes.delta", "response.animation_blendshapes.done", - "response.animation_viseme.delta", "response.animation_viseme.done", and - "response.video.delta". - :vartype type: str or ~azure.ai.projects.models.RealtimeServerEventType + type: Literal["programmatic_tool_calling"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``programmatic_tool_calling``. Required. Default value is + \"programmatic_tool_calling\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["programmatic_tool_calling"] = "programmatic_tool_calling" + + +class LiveSpecificWebSearchParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificWebSearchParam. + + :ivar type: The tool to call. Always ``web_search``. Required. Default value is "web_search". + :vartype type: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"conversation.created\", \"conversation.item.created\", - \"conversation.item.deleted\", \"conversation.item.input_audio_transcription.completed\", - \"conversation.item.input_audio_transcription.delta\", - \"conversation.item.input_audio_transcription.failed\", \"conversation.item.retrieved\", - \"conversation.item.truncated\", \"error\", \"input_audio_buffer.cleared\", - \"input_audio_buffer.committed\", \"input_audio_buffer.dtmf_event_received\", - \"input_audio_buffer.speech_started\", \"input_audio_buffer.speech_stopped\", - \"rate_limits.updated\", \"response.output_audio.delta\", \"response.output_audio.done\", - \"response.output_audio_transcript.delta\", \"response.output_audio_transcript.done\", - \"response.content_part.added\", \"response.content_part.done\", \"response.created\", - \"response.done\", \"response.function_call_arguments.delta\", - \"response.function_call_arguments.done\", \"response.output_item.added\", - \"response.output_item.done\", \"response.output_text.delta\", \"response.output_text.done\", - \"session.created\", \"session.updated\", \"output_audio_buffer.started\", - \"output_audio_buffer.stopped\", \"output_audio_buffer.cleared\", \"conversation.item.added\", - \"conversation.item.done\", \"input_audio_buffer.timeout_triggered\", - \"conversation.item.input_audio_transcription.segment\", \"mcp_list_tools.in_progress\", - \"mcp_list_tools.completed\", \"mcp_list_tools.failed\", \"response.mcp_call_arguments.delta\", - \"response.mcp_call_arguments.done\", \"response.mcp_call.in_progress\", - \"response.mcp_call.completed\", \"response.mcp_call.failed\", \"warning\", - \"session.subagent.started\", \"session.subagent.completed\", \"session.subagent.aborted\", - \"session.avatar.connecting\", \"session.avatar.switch_to_speaking\", - \"session.avatar.switch_to_idle\", \"rtc.call.sdp.created\", \"rtc.call.error\", - \"response.audio_timestamp.delta\", \"response.audio_timestamp.done\", - \"response.animation_blendshapes.delta\", \"response.animation_blendshapes.done\", - \"response.animation_viseme.delta\", \"response.animation_viseme.done\", and - \"response.video.delta\".""" + type: Literal["web_search"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``web_search``. Required. Default value is \"web_search\".""" - @overload - def __init__( - self, - *, - type: str, - ) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["web_search"] = "web_search" - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ + +class LiveSpecificWebSearchPreviewParam(_Model): # pylint: disable=docstring-missing-param + """LiveSpecificWebSearchPreviewParam. + + :ivar type: The tool to call. Always ``web_search_preview``. Required. Default value is + "web_search_preview". + :vartype type: str + """ + + type: Literal["web_search_preview"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool to call. Always ``web_search_preview``. Required. Default value is + \"web_search_preview\".""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["web_search_preview"] = "web_search_preview" -class RealtimeServerEventConversationItemAdded( - RealtimeServerEvent, discriminator="conversation.item.added" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Sent by the server when an Item is added to the default Conversation. This can happen in - several cases: +class LiveToolSearchToolInputParam(_Model): # pylint: disable=docstring-missing-param + """LiveToolSearchToolInputParam. - * When the client sends a `conversation.item.create` event. - * When the input audio buffer is committed. In this case the item will be a user message containing the audio from - the buffer. - * When the model is generating a Response. In this case the `conversation.item.added` event will be sent when the - model starts generating a specific Item, and thus it will not yet have any content (and `status` will be - `in_progress`). The event will include the full content of the Item (except when model is generating a Response) - except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if necessary. + :ivar type: Required. Default value is "tool_search". + :vartype type: str + """ - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.added``. Required. - CONVERSATION_ITEM_ADDED. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_ADDED - :ivar previous_item_id: - :vartype previous_item_id: str - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + type: Literal["tool_search"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"tool_search\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["tool_search"] = "tool_search" + + +class LiveTransportCallError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LiveTransportCallError. + + :ivar type: Required. Default value is "call_error". + :vartype type: str + :ivar code: The call setup failure code. Required. + :vartype code: str + :ivar message: Required. + :vartype message: str + :ivar param: The parameter related to the error, if any. Empty when no parameter applies. + :vartype param: str """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_ADDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.added``. Required. CONVERSATION_ITEM_ADDED.""" - previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal["call_error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"call_error\".""" + code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The call setup failure code. Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" + param: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The parameter related to the error, if any. Empty when no parameter applies.""" @overload def __init__( self, *, - event_id: str, - item: "_models.RealtimeConversationItem", - previous_item_id: Optional[str] = None, + code: str, + message: str, + param: Optional[str] = None, ) -> None: ... @overload @@ -19231,47 +20027,59 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_ADDED # type: ignore + self.type: Literal["call_error"] = "call_error" -class RealtimeServerEventConversationItemCreated( - RealtimeServerEvent, discriminator="conversation.item.created" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when a conversation item is created. There are several scenarios that produce this - event: +class LiveWebSearchToolInputParam(_Model): # pylint: disable=docstring-missing-param + """A web search tool available to the Live session’s Responses backend. - * The server is generating a Response, which if successful will produce either one or two Items, which will be of - type `message` (role `assistant`) or type `function_call`. - * The input audio buffer has been committed, either by the client or the server (in `server_vad` mode). The server - will take the content of the input audio buffer and add it to a new user message Item. - * The client has sent a `conversation.item.create` event to add a new Item to the Conversation. + :ivar type: The tool type. Always ``web_search``. Required. Default value is "web_search". + :vartype type: str + """ - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.created``. Required. - CONVERSATION_ITEM_CREATED. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_CREATED - :ivar previous_item_id: - :vartype previous_item_id: str - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + type: Literal["web_search"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tool type. Always ``web_search``. Required. Default value is \"web_search\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["web_search"] = "web_search" + + +class LocalShellToolParam( + Tool, discriminator="local_shell" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """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: Deprecated. This property is deprecated and will be removed in a future version. + :vartype name: str + :ivar description: Deprecated. This property is deprecated and will be removed in a future + version. + :vartype description: str + :ivar tool_configs: Deprecated. This property is deprecated and will be removed in a future + version. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.created``. Required. CONVERSATION_ITEM_CREATED.""" - previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + 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"]) + """Deprecated. This property is deprecated and will be removed in a future version.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Deprecated. This property is deprecated and will be removed in a future version.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Deprecated. This property is deprecated and will be removed in a future version.""" @overload def __init__( self, *, - event_id: str, - item: "_models.RealtimeConversationItem", - previous_item_id: Optional[str] = None, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -19283,38 +20091,34 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_CREATED # type: ignore + self.type = ToolType.LOCAL_SHELL # type: ignore -class RealtimeServerEventConversationItemDeleted( - RealtimeServerEvent, discriminator="conversation.item.deleted" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an item in the conversation is deleted by the client with a - ``conversation.item.delete`` event. This event is used to synchronize the server's - understanding of the conversation history with the client's view. +class LocalSkillParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """LocalSkillParam. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.deleted``. Required. - CONVERSATION_ITEM_DELETED. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_DELETED - :ivar item_id: The ID of the item that was deleted. Required. - :vartype item_id: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DELETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.deleted``. Required. CONVERSATION_ITEM_DELETED.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item that was deleted. Required.""" + 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, *, - event_id: str, - item_id: str, + name: str, + description: str, + path: str, ) -> None: ... @overload @@ -19326,42 +20130,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_DELETED # type: ignore -class RealtimeServerEventConversationItemDone( - RealtimeServerEvent, discriminator="conversation.item.done" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when a conversation item is finalized. The event will include the full content of the - Item except for audio data, which can be retrieved separately with a - ``conversation.item.retrieve`` event if needed. +class LogProbProperties(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A log probability object. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.done``. Required. - CONVERSATION_ITEM_DONE. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_DONE - :ivar previous_item_id: - :vartype previous_item_id: str - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + :ivar token: The token that was used to generate the log probability. Required. + :vartype token: str + :ivar logprob: The log probability of the token. Required. + :vartype logprob: float + :ivar bytes: The bytes that were used to generate the log probability. Required. + :vartype bytes: list[int] """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.done``. Required. CONVERSATION_ITEM_DONE.""" - previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + token: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The token that was used to generate the log probability. Required.""" + logprob: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The log probability of the token. Required.""" + bytes: list[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The bytes that were used to generate the log probability. Required.""" @overload def __init__( self, *, - event_id: str, - item: "_models.RealtimeConversationItem", - previous_item_id: Optional[str] = None, + token: str, + logprob: float, + bytes: list[int], ) -> None: ... @overload @@ -19373,88 +20168,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_DONE # type: ignore -class RealtimeServerEventConversationItemInputAudioTranscriptionCompleted( - RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.completed" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """This event is the output of audio transcription for user audio written to the user audio - buffer. Transcription begins when the input audio buffer is committed by the client or server - (when VAD is enabled). Transcription runs asynchronously with Response creation, so this event - may come before or after the Response events. Realtime API models accept audio natively, and - thus input transcription is a separate process run on a separate ASR (Automatic Speech - Recognition) model. The transcript may diverge somewhat from the model's interpretation, and - should be treated as a rough guide. +class LoraConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Adapter-specific metadata for LoRA models. Drives serving engine configuration at deployment + time. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.input_audio_transcription.completed``. - Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED. - :vartype type: str or - ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED - :ivar item_id: The ID of the item containing the audio that is being transcribed. Required. - :vartype item_id: str - :ivar content_index: The index of the content part containing the audio. Required. - :vartype content_index: int - :ivar transcript: The transcribed text. Required. - :vartype transcript: str - :ivar languages: The languages detected in the audio. Returned by ``gpt-transcribe``. An empty - array indicates that no language could be reliably detected. - :vartype languages: list[~azure.ai.projects.models.TranscriptionLanguage] - :ivar logprobs: - :vartype logprobs: list[~azure.ai.projects.models.LogProbProperties] - :ivar usage: Usage statistics for the transcription, this is billed according to the ASR - model's pricing rather than the realtime model's pricing. Required. Is either a - TranscriptTextUsageTokens type or a TranscriptTextUsageDuration type. - :vartype usage: ~azure.ai.projects.models.TranscriptTextUsageTokens or - ~azure.ai.projects.models.TranscriptTextUsageDuration - :ivar phrases: Phrase-level transcription timing and confidence details. - :vartype phrases: list[~azure.ai.projects.models.VoiceAgentTranscriptionPhrase] + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.input_audio_transcription.completed``. Required. - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item containing the audio that is being transcribed. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part containing the audio. Required.""" - transcript: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The transcribed text. Required.""" - languages: Optional[list["_models.TranscriptionLanguage"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The languages detected in the audio. Returned by ``gpt-transcribe``. An empty array indicates - that no language could be reliably detected.""" - logprobs: Optional[list["_models.LogProbProperties"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - usage: Union["_models.TranscriptTextUsageTokens", "_models.TranscriptTextUsageDuration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Usage statistics for the transcription, this is billed according to the ASR model's pricing - rather than the realtime model's pricing. Required. Is either a TranscriptTextUsageTokens type - or a TranscriptTextUsageDuration type.""" - phrases: Optional[list["_models.VoiceAgentTranscriptionPhrase"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + 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"] ) - """Phrase-level transcription timing and confidence details.""" + """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, *, - event_id: str, - item_id: str, - content_index: int, - transcript: str, - usage: Union["_models.TranscriptTextUsageTokens", "_models.TranscriptTextUsageDuration"], - languages: Optional[list["_models.TranscriptionLanguage"]] = None, - logprobs: Optional[list["_models.LogProbProperties"]] = None, - phrases: Optional[list["_models.VoiceAgentTranscriptionPhrase"]] = None, + rank: Optional[int] = None, + alpha: Optional[int] = None, + target_modules: Optional[list[str]] = None, + dropout: Optional[float] = None, ) -> None: ... @overload @@ -19466,55 +20216,29 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED # type: ignore -class RealtimeServerEventConversationItemInputAudioTranscriptionDelta( - RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.delta" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the text value of an input audio transcription content part is updated with - incremental transcription results. +class ManagedAgentIdentityBlueprintReference( + AgentBlueprintReference, discriminator="ManagedAgentIdentityBlueprint" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """ManagedAgentIdentityBlueprintReference. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.input_audio_transcription.delta``. - Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA. - :vartype type: str or - ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA - :ivar item_id: The ID of the item containing the audio that is being transcribed. Required. - :vartype item_id: str - :ivar content_index: The index of the content part in the item's content array. - :vartype content_index: int - :ivar delta: The text delta. - :vartype delta: str - :ivar logprobs: - :vartype logprobs: list[~azure.ai.projects.models.LogProbProperties] + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.input_audio_transcription.delta``. Required. - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item containing the audio that is being transcribed. Required.""" - content_index: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array.""" - delta: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The text delta.""" - logprobs: Optional[list["_models.LogProbProperties"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) + 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, *, - event_id: str, - item_id: str, - content_index: Optional[int] = None, - delta: Optional[str] = None, - logprobs: Optional[list["_models.LogProbProperties"]] = None, + blueprint_id: str, ) -> None: ... @overload @@ -19526,53 +20250,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA # type: ignore + self.type = AgentBlueprintReferenceType.MANAGED_AGENT_IDENTITY_BLUEPRINT # type: ignore -class RealtimeServerEventConversationItemInputAudioTranscriptionFailed( - RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.failed" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when input audio transcription is configured, and a transcription request for a user - message failed. These events are separate from other ``error`` events so that the client can - identify the related Item. +class ManagedAzureAISearchIndex( + Index, discriminator="ManagedAzureSearch" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Managed Azure AI Search Index Definition. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.input_audio_transcription.failed``. - Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED. - :vartype type: str or - ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED - :ivar item_id: The ID of the user message item. Required. - :vartype item_id: str - :ivar content_index: The index of the content part containing the audio. Required. - :vartype content_index: int - :ivar error: Details of the transcription error. Required. - :vartype error: - ~azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.input_audio_transcription.failed``. Required. - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the user message item. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part containing the audio. Required.""" - error: "_models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Details of the transcription error. Required.""" + 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, *, - event_id: str, - item_id: str, - content_index: int, - error: "_models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError", + vector_store_id: str, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -19584,37 +20297,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED # type: ignore + self.type = IndexType.MANAGED_AZURE_SEARCH # type: ignore -class RealtimeServerEventConversationItemInputAudioTranscriptionFailedError( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeServerEventConversationItemInputAudioTranscriptionFailedError. +class MCPListToolsTool(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """MCP list tools tool. - :ivar type: - :vartype type: str - :ivar code: - :vartype code: str - :ivar message: - :vartype message: str - :ivar param: - :vartype param: str + :ivar name: The name of the tool. Required. + :vartype name: str + :ivar description: + :vartype description: str + :ivar input_schema: The JSON schema describing the tool's input. Required. + :vartype input_schema: ~azure.ai.projects.models.MCPListToolsToolInputSchema + :ivar annotations: + :vartype annotations: ~azure.ai.projects.models.MCPListToolsToolAnnotations """ - type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - param: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the tool. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input_schema: "_models.MCPListToolsToolInputSchema" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The JSON schema describing the tool's input. Required.""" + annotations: Optional["_models.MCPListToolsToolAnnotations"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) @overload def __init__( self, *, - type: Optional[str] = None, - code: Optional[str] = None, - message: Optional[str] = None, - param: Optional[str] = None, + name: str, + input_schema: "_models.MCPListToolsToolInputSchema", + description: Optional[str] = None, + annotations: Optional["_models.MCPListToolsToolAnnotations"] = None, ) -> None: ... @overload @@ -19628,65 +20345,176 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RealtimeServerEventConversationItemInputAudioTranscriptionSegment( - RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.segment" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an input audio transcription segment is identified for an item. +class MCPListToolsToolAnnotations(_Model): + """MCPListToolsToolAnnotations.""" - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.input_audio_transcription.segment``. - Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT. - :vartype type: str or - ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT - :ivar item_id: The ID of the item containing the input audio content. Required. - :vartype item_id: str - :ivar content_index: The index of the input audio content part within the item. Required. - :vartype content_index: int - :ivar text: The text for this segment. Required. - :vartype text: str - :ivar id: The segment identifier. Required. - :vartype id: str - :ivar speaker: The detected speaker label for this segment. Required. - :vartype speaker: str - :ivar start: Start time of the segment in seconds. Required. - :vartype start: float - :ivar end: End time of the segment in seconds. Required. - :vartype end: float + +class MCPListToolsToolInputSchema(_Model): + """MCPListToolsToolInputSchema.""" + + +class McpProtocolConfiguration(_Model): + """Configuration specific to the MCP protocol.""" + + +class MCPTool(Tool, discriminator="mcp"): # pylint: disable=docstring-keyword-should-match-keyword-only + """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``, ``connector_id``, or + ``tunnel_id`` must be provided. + :vartype server_url: str + :ivar connector_id: Identifier for service connectors, like those available in ChatGPT. One of + ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. Learn more about service + connectors `here + `_. This field + is deprecated for models released after September 1, 2026. Use ``server_url`` to connect to a + remote MCP server, or ``tunnel_id`` to connect through a Secure MCP Tunnel. 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 tunnel_id: The Secure MCP Tunnel ID to use instead of a direct server URL. One of + ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. + :vartype tunnel_id: 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 allowed_callers: + :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] + :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 defer_loading: Whether this MCP tool is deferred and discovered via tool search. + :vartype defer_loading: bool + :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: Deprecated. This property is deprecated and will be removed in a future + version. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.input_audio_transcription.segment``. Required. - CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item containing the input audio content. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the input audio content part within the item. Required.""" - text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The text for this segment. Required.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The segment identifier. Required.""" - speaker: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The detected speaker label for this segment. Required.""" - start: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Start time of the segment in seconds. Required.""" - end: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """End time of the segment in seconds. Required.""" + 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``, ``connector_id``, or ``tunnel_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``, + ``connector_id``, or ``tunnel_id`` must be provided. Learn more about service connectors `here + `_. This field + is deprecated for models released after September 1, 2026. Use ``server_url`` to connect to a + remote MCP server, or ``tunnel_id`` to connect through a Secure MCP Tunnel. 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\"]""" + tunnel_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Secure MCP Tunnel ID to use instead of a direct server URL. One of ``server_url``, + ``connector_id``, or ``tunnel_id`` must be provided.""" + 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.""" + allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + 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\"]""" + defer_loading: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether this MCP tool is deferred and discovered via tool search.""" + 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"] + ) + """Deprecated. This property is deprecated and will be removed in a future version.""" @overload def __init__( self, *, - event_id: str, - item_id: str, - content_index: int, - text: str, - id: str, # pylint: disable=redefined-builtin - speaker: str, - start: float, - end: float, + 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, + tunnel_id: Optional[str] = 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, + allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = None, + require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = None, + defer_loading: Optional[bool] = None, + project_connection_id: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -19698,39 +20526,170 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT # type: ignore + self.type = ToolType.MCP # type: ignore -class RealtimeServerEventConversationItemRetrieved( - RealtimeServerEvent, discriminator="conversation.item.retrieved" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when a conversation item is retrieved with ``conversation.item.retrieve``. This is - provided as a way to fetch the server's representation of an item, for example to get access to - the post-processed audio data after noise cancellation and VAD. It includes the full content of - the Item, including audio data. +class MCPToolboxTool(ToolboxTool, discriminator="mcp"): # pylint: disable=docstring-keyword-should-match-keyword-only + """An MCP tool stored in a toolbox. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.retrieved``. Required. - CONVERSATION_ITEM_RETRIEVED. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_RETRIEVED - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + :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 type: 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``, ``connector_id``, or + ``tunnel_id`` must be provided. + :vartype server_url: str + :ivar connector_id: Identifier for service connectors, like those available in ChatGPT. One of + ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. Learn more about service + connectors `here + `_. This field + is deprecated for models released after September 1, 2026. Use ``server_url`` to connect to a + remote MCP server, or ``tunnel_id`` to connect through a Secure MCP Tunnel. 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 tunnel_id: The Secure MCP Tunnel ID to use instead of a direct server URL. One of + ``server_url``, ``connector_id``, or ``tunnel_id`` must be provided. + :vartype tunnel_id: 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 allowed_callers: + :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] + :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 defer_loading: Whether this MCP tool is deferred and discovered via tool search. + :vartype defer_loading: bool + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_RETRIEVED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.retrieved``. Required. CONVERSATION_ITEM_RETRIEVED.""" - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + type: Literal[ToolboxToolType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """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``, ``connector_id``, or ``tunnel_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``, + ``connector_id``, or ``tunnel_id`` must be provided. Learn more about service connectors `here + `_. This field + is deprecated for models released after September 1, 2026. Use ``server_url`` to connect to a + remote MCP server, or ``tunnel_id`` to connect through a Secure MCP Tunnel. 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\"]""" + tunnel_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Secure MCP Tunnel ID to use instead of a direct server URL. One of ``server_url``, + ``connector_id``, or ``tunnel_id`` must be provided.""" + 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.""" + allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + 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\"]""" + defer_loading: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether this MCP tool is deferred and discovered via tool search.""" + 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.""" @overload def __init__( self, *, - event_id: str, - item: "_models.RealtimeConversationItem", + server_label: str, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + 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, + tunnel_id: Optional[str] = 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, + allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = None, + require_approval: Optional[Union["_models.MCPToolRequireApproval", Literal["always"], Literal["never"]]] = None, + defer_loading: Optional[bool] = None, + project_connection_id: Optional[str] = None, ) -> None: ... @overload @@ -19742,58 +20701,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_RETRIEVED # type: ignore + self.type = ToolboxToolType.MCP # type: ignore -class RealtimeServerEventConversationItemTruncated( - RealtimeServerEvent, discriminator="conversation.item.truncated" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an earlier assistant audio message item is truncated by the client with a - ``conversation.item.truncate`` event. This event is used to synchronize the server's - understanding of the audio with the client's playback. This action will truncate the audio and - remove the server-side text transcript to ensure there is no text in the context that hasn't - been heard by the user. +class MCPToolFilter(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """MCP tool filter. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``conversation.item.truncated``. Required. - CONVERSATION_ITEM_TRUNCATED. - :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_TRUNCATED - :ivar item_id: The ID of the assistant message item that was truncated. Required. - :vartype item_id: str - :ivar content_index: The index of the content part that was truncated. Required. - :vartype content_index: int - :ivar audio_end_ms: The duration up to which the audio was truncated, in milliseconds. - Required. - :vartype audio_end_ms: int - :ivar item: The assistant message after truncation, when the service returns the updated item. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_TRUNCATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``conversation.item.truncated``. Required. CONVERSATION_ITEM_TRUNCATED.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the assistant message item that was truncated. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part that was truncated. Required.""" - audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The duration up to which the audio was truncated, in milliseconds. Required.""" - item: Optional["_models.RealtimeConversationItem"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The assistant message after truncation, when the service returns the updated item.""" + 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, *, - event_id: str, - item_id: str, - content_index: int, - audio_end_ms: int, - item: Optional["_models.RealtimeConversationItem"] = None, + tool_names: Optional[list[str]] = None, + read_only: Optional[bool] = None, ) -> None: ... @overload @@ -19805,37 +20741,26 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.CONVERSATION_ITEM_TRUNCATED # type: ignore -class RealtimeServerEventError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when an error occurs, which could be a client problem or a server problem. Most errors - are recoverable and the session will stay open, we recommend to implementors to monitor and log - error messages by default. +class MCPToolRequireApproval(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """MCPToolRequireApproval. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``error``. Required. Default value is "error". - :vartype type: str - :ivar error: Details of the error. Required. - :vartype error: ~azure.ai.projects.models.RealtimeServerEventErrorError + :ivar always: + :vartype always: ~azure.ai.projects.models.MCPToolFilter + :ivar never: + :vartype never: ~azure.ai.projects.models.MCPToolFilter """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal["error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The event type, must be ``error``. Required. Default value is \"error\".""" - error: "_models.RealtimeServerEventErrorError" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Details of the error. Required.""" + 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, *, - event_id: str, - error: "_models.RealtimeServerEventErrorError", + always: Optional["_models.MCPToolFilter"] = None, + never: Optional["_models.MCPToolFilter"] = None, ) -> None: ... @overload @@ -19847,41 +20772,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["error"] = "error" -class RealtimeServerEventErrorError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """RealtimeServerEventErrorError. +class MemoryOperation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Represents a single memory operation (create, update, or delete) performed on a memory item. - :ivar type: Required. - :vartype type: str - :ivar code: - :vartype code: str - :ivar message: Required. - :vartype message: str - :ivar param: - :vartype param: str - :ivar event_id: - :vartype event_id: 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 """ - type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - param: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + kind: Union[str, "_models.MemoryOperationKind"] = 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.""" @overload def __init__( self, *, - type: str, - message: str, - code: Optional[str] = None, - param: Optional[str] = None, - event_id: Optional[str] = None, + kind: Union[str, "_models.MemoryOperationKind"], + memory_item: "_models.MemoryItem", ) -> None: ... @overload @@ -19895,29 +20811,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RealtimeServerEventInputAudioBufferCleared( - RealtimeServerEvent, discriminator="input_audio_buffer.cleared" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the input audio buffer is cleared by the client with a - ``input_audio_buffer.clear`` event. +class MemorySearchItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A retrieved memory item from memory search. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.cleared``. Required. - INPUT_AUDIO_BUFFER_CLEARED. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_CLEARED + :ivar memory_item: Retrieved memory item. Required. + :vartype memory_item: ~azure.ai.projects.models.MemoryItem """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_CLEARED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.cleared``. Required. INPUT_AUDIO_BUFFER_CLEARED.""" + memory_item: "_models.MemoryItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Retrieved memory item. Required.""" @overload def __init__( self, *, - event_id: str, + memory_item: "_models.MemoryItem", ) -> None: ... @overload @@ -19929,43 +20837,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.INPUT_AUDIO_BUFFER_CLEARED # type: ignore -class RealtimeServerEventInputAudioBufferCommitted( - RealtimeServerEvent, discriminator="input_audio_buffer.committed" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an input audio buffer is committed, either by the client or automatically in - server VAD mode. The ``item_id`` property is the ID of the user message item that will be - created, thus a ``conversation.item.created`` event will also be sent to the client. +class MemorySearchOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Memory search options. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.committed``. Required. - INPUT_AUDIO_BUFFER_COMMITTED. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_COMMITTED - :ivar previous_item_id: - :vartype previous_item_id: str - :ivar item_id: The ID of the user message item that will be created. Required. - :vartype item_id: str + :ivar max_memories: Maximum number of memory items to return. + :vartype max_memories: int """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_COMMITTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.committed``. Required. - INPUT_AUDIO_BUFFER_COMMITTED.""" - previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the user message item that will be created. Required.""" + max_memories: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of memory items to return.""" @overload def __init__( self, *, - event_id: str, - item_id: str, - previous_item_id: Optional[str] = None, + max_memories: Optional[int] = None, ) -> None: ... @overload @@ -19977,54 +20865,52 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.INPUT_AUDIO_BUFFER_COMMITTED # type: ignore -class RealtimeServerEventInputAudioBufferSpeechStarted( - RealtimeServerEvent, discriminator="input_audio_buffer.speech_started" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Sent by the server when in ``server_vad`` mode to indicate that speech has been detected in the - audio buffer. This can happen any time audio is added to the buffer (unless speech is already - detected). The client may want to use this event to interrupt audio playback or provide visual - feedback to the user. The client should expect to receive a - ``input_audio_buffer.speech_stopped`` event when speech stops. The ``item_id`` property is the - ID of the user message item that will be created when speech stops and will also be included in - the ``input_audio_buffer.speech_stopped`` event (unless the client manually commits the audio - buffer during VAD activation). +class MemorySearchPreviewTool( + Tool, discriminator="memory_search_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A tool for integrating memories into the agent. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.speech_started``. Required. - INPUT_AUDIO_BUFFER_SPEECH_STARTED. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_SPEECH_STARTED - :ivar audio_start_ms: Milliseconds from the start of all audio written to the buffer during the - session when speech was first detected. This will correspond to the beginning of audio sent to - the model, and thus includes the ``prefix_padding_ms`` configured in the Session. Required. - :vartype audio_start_ms: int - :ivar item_id: The ID of the user message item that will be created when speech stops. - Required. - :vartype item_id: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.speech_started``. Required. - INPUT_AUDIO_BUFFER_SPEECH_STARTED.""" - audio_start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Milliseconds from the start of all audio written to the buffer during the session when speech - was first detected. This will correspond to the beginning of audio sent to the model, and thus - includes the ``prefix_padding_ms`` configured in the Session. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the user message item that will be created when speech stops. Required.""" + 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.""" @overload def __init__( self, *, - event_id: str, - audio_start_ms: int, - item_id: str, + memory_store_name: str, + scope: str, + search_options: Optional["_models.MemorySearchOptions"] = None, + update_delay: Optional[int] = None, ) -> None: ... @overload @@ -20036,48 +20922,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED # type: ignore + self.type = ToolType.MEMORY_SEARCH_PREVIEW # type: ignore -class RealtimeServerEventInputAudioBufferSpeechStopped( - RealtimeServerEvent, discriminator="input_audio_buffer.speech_stopped" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned in ``server_vad`` mode when the server detects the end of speech in the audio buffer. - The server will also send an ``conversation.item.created`` event with the user message item - that is created from the audio buffer. +class MemoryStoreDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Base definition for memory store configurations. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.speech_stopped``. Required. - INPUT_AUDIO_BUFFER_SPEECH_STOPPED. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_SPEECH_STOPPED - :ivar audio_end_ms: Milliseconds since the session started when speech stopped. This will - correspond to the end of audio sent to the model, and thus includes the - ``min_silence_duration_ms`` configured in the Session. Required. - :vartype audio_end_ms: int - :ivar item_id: The ID of the user message item that will be created. Required. - :vartype item_id: 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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STOPPED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.speech_stopped``. Required. - INPUT_AUDIO_BUFFER_SPEECH_STOPPED.""" - audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Milliseconds since the session started when speech stopped. This will correspond to the end of - audio sent to the model, and thus includes the ``min_silence_duration_ms`` configured in the - Session. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the user message item that will be created. Required.""" + __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, *, - event_id: str, - audio_end_ms: int, - item_id: str, + kind: str, ) -> None: ... @overload @@ -20089,61 +20955,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STOPPED # type: ignore -class RealtimeServerEventInputAudioBufferTimeoutTriggered( - RealtimeServerEvent, discriminator="input_audio_buffer.timeout_triggered" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the Server VAD timeout is triggered for the input audio buffer. This is - configured with ``idle_timeout_ms`` in the ``turn_detection`` settings of the session, and it - indicates that there hasn't been any speech detected for the configured duration. The - ``audio_start_ms`` and ``audio_end_ms`` fields indicate the segment of audio after the last - model response up to the triggering time, as an offset from the beginning of audio written to - the input audio buffer. This means it demarcates the segment of audio that was silent and the - difference between the start and end values will roughly match the configured timeout. The - empty audio will be committed to the conversation as an ``input_audio`` item (there will be a - ``input_audio_buffer.committed`` event) and a model response will be generated. There may be - speech that didn't trigger VAD but is still detected by the model, so the model may respond - with something relevant to the conversation or a prompt to continue speaking. +class MemoryStoreDefaultDefinition( + MemoryStoreDefinition, discriminator="default" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Default memory store implementation. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``input_audio_buffer.timeout_triggered``. Required. - INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED - :ivar audio_start_ms: Millisecond offset of audio written to the input audio buffer that was - after the playback time of the last model response. Required. - :vartype audio_start_ms: int - :ivar audio_end_ms: Millisecond offset of audio written to the input audio buffer at the time - the timeout was triggered. Required. - :vartype audio_end_ms: int - :ivar item_id: The ID of the item associated with this segment. Required. - :vartype item_id: 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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``input_audio_buffer.timeout_triggered``. Required. - INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED.""" - audio_start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Millisecond offset of audio written to the input audio buffer that was after the playback time - of the last model response. Required.""" - audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Millisecond offset of audio written to the input audio buffer at the time the timeout was - triggered. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item associated with this segment. 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, *, - event_id: str, - audio_start_ms: int, - audio_end_ms: int, - item_id: str, + chat_model: str, + embedding_model: str, + options: Optional["_models.MemoryStoreDefaultOptions"] = None, ) -> None: ... @overload @@ -20155,36 +21002,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED # type: ignore + self.kind = MemoryStoreKind.DEFAULT # type: ignore -class RealtimeServerEventMCPListToolsCompleted( - RealtimeServerEvent, discriminator="mcp_list_tools.completed" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when listing MCP tools has completed for an item. +class MemoryStoreDefaultOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Default memory store configurations. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``mcp_list_tools.completed``. Required. - MCP_LIST_TOOLS_COMPLETED. - :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS_COMPLETED - :ivar item_id: The ID of the MCP list tools item. Required. - :vartype item_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. + The service defaults to ``true`` if a value is not specified by the caller. + :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: ~datetime.timedelta """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``mcp_list_tools.completed``. Required. MCP_LIST_TOOLS_COMPLETED.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP list tools item. 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. The service defaults to ``true`` if + a value is not specified by the caller.""" + default_ttl_seconds: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + ) + """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, *, - event_id: str, - item_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[datetime.timedelta] = None, ) -> None: ... @overload @@ -20196,35 +21060,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.MCP_LIST_TOOLS_COMPLETED # type: ignore -class RealtimeServerEventMCPListToolsFailed( - RealtimeServerEvent, discriminator="mcp_list_tools.failed" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when listing MCP tools has failed for an item. +class MemoryStoreDeleteScopeResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Response for deleting memories from a scope. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``mcp_list_tools.failed``. Required. MCP_LIST_TOOLS_FAILED. - :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS_FAILED - :ivar item_id: The ID of the MCP list tools item. Required. - :vartype item_id: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``mcp_list_tools.failed``. Required. MCP_LIST_TOOLS_FAILED.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP list tools item. 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, *, - event_id: str, - item_id: str, + object: Literal[MemoryStoreObjectType.MEMORY_STORE_SCOPE_DELETED], + name: str, + scope: str, + deleted: bool, ) -> None: ... @overload @@ -20236,36 +21106,65 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.MCP_LIST_TOOLS_FAILED # type: ignore -class RealtimeServerEventMCPListToolsInProgress( - RealtimeServerEvent, discriminator="mcp_list_tools.in_progress" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when listing MCP tools is in progress for an item. +class MemoryStoreDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A memory store that can store and retrieve user memories. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``mcp_list_tools.in_progress``. Required. - MCP_LIST_TOOLS_IN_PROGRESS. - :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS_IN_PROGRESS - :ivar item_id: The ID of the MCP list tools item. Required. - :vartype item_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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_IN_PROGRESS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``mcp_list_tools.in_progress``. Required. MCP_LIST_TOOLS_IN_PROGRESS.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP list tools item. Required.""" + 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" + ) + """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, *, - event_id: str, - item_id: str, + 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 @@ -20277,40 +21176,52 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.MCP_LIST_TOOLS_IN_PROGRESS # type: ignore -class RealtimeServerEventOutputAudioBufferCleared( - RealtimeServerEvent, discriminator="output_audio_buffer.cleared" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """**WebRTC/SIP Only:** Emitted when the output audio buffer is cleared. This happens either in - VAD mode when the user has interrupted (``input_audio_buffer.speech_started``), or when the - client has emitted the ``output_audio_buffer.clear`` event to manually cut off the current - audio response. `Learn more - `_. +class MemoryStoreOperationUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Usage statistics of a memory store operation. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``output_audio_buffer.cleared``. Required. - OUTPUT_AUDIO_BUFFER_CLEARED. - :vartype type: str or ~azure.ai.projects.models.OUTPUT_AUDIO_BUFFER_CLEARED - :ivar response_id: The unique ID of the response that produced the audio. Required. - :vartype response_id: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.OUTPUT_AUDIO_BUFFER_CLEARED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``output_audio_buffer.cleared``. Required. OUTPUT_AUDIO_BUFFER_CLEARED.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the response that produced the audio. Required.""" + 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, *, - event_id: str, - response_id: str, + embedding_tokens: int, + input_tokens: int, + input_tokens_details: "_models.ResponseUsageInputTokensDetails", + output_tokens: int, + output_tokens_details: "_models.ResponseUsageOutputTokensDetails", + total_tokens: int, ) -> None: ... @overload @@ -20322,40 +21233,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.OUTPUT_AUDIO_BUFFER_CLEARED # type: ignore -class RealtimeServerEventRateLimitsUpdated( - RealtimeServerEvent, discriminator="rate_limits.updated" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Emitted at the beginning of a Response to indicate the updated rate limits. When a Response is - created some tokens will be "reserved" for the output tokens, the rate limits shown here - reflect that reservation, which is then adjusted accordingly once the Response is completed. +class MemoryStoreSearchResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Memory search response. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``rate_limits.updated``. Required. RATE_LIMITS_UPDATED. - :vartype type: str or ~azure.ai.projects.models.RATE_LIMITS_UPDATED - :ivar rate_limits: List of rate limit information. Required. - :vartype rate_limits: - list[~azure.ai.projects.models.RealtimeServerEventRateLimitsUpdatedRateLimits] + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RATE_LIMITS_UPDATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``rate_limits.updated``. Required. RATE_LIMITS_UPDATED.""" - rate_limits: list["_models.RealtimeServerEventRateLimitsUpdatedRateLimits"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """List of rate limit information. Required.""" + 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, *, - event_id: str, - rate_limits: list["_models.RealtimeServerEventRateLimitsUpdatedRateLimits"], + search_id: str, + memories: list["_models.MemorySearchItem"], + usage: "_models.MemoryStoreOperationUsage", ) -> None: ... @overload @@ -20367,40 +21273,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RATE_LIMITS_UPDATED # type: ignore -class RealtimeServerEventRateLimitsUpdatedRateLimits( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeServerEventRateLimitsUpdatedRateLimits. +class MemoryStoreUpdateCompletedResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Memory update result. - :ivar name: Is either a Literal["requests"] type or a Literal["tokens"] type. - :vartype name: str or str - :ivar limit: - :vartype limit: int - :ivar remaining: - :vartype remaining: int - :ivar reset_seconds: - :vartype reset_seconds: float + :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 """ - name: Optional[Literal["requests", "tokens"]] = rest_field( + memory_operations: list["_models.MemoryOperation"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Is either a Literal[\"requests\"] type or a Literal[\"tokens\"] type.""" - limit: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - remaining: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - reset_seconds: Optional[float] = 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.""" @overload def __init__( self, *, - name: Optional[Literal["requests", "tokens"]] = None, - limit: Optional[int] = None, - remaining: Optional[int] = None, - reset_seconds: Optional[float] = None, + memory_operations: list["_models.MemoryOperation"], + usage: "_models.MemoryStoreOperationUsage", ) -> None: ... @overload @@ -20414,53 +21311,51 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RealtimeServerEventResponseAudioDelta( - RealtimeServerEvent, discriminator="response.output_audio.delta" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when the model-generated audio is updated. +class MemoryStoreUpdateResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Provides the status of a memory store update operation. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_audio.delta``. Required. - RESPONSE_OUTPUT_AUDIO_DELTA. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_DELTA - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar delta: Base64-encoded audio data delta. Required. - :vartype delta: bytes + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_audio.delta``. Required. RESPONSE_OUTPUT_AUDIO_DELTA.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - delta: bytes = rest_field(visibility=["read", "create", "update", "delete", "query"], format="base64") - """Base64-encoded audio data delta. 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, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - delta: bytes, + 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 @@ -20472,52 +21367,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DELTA # type: ignore -class RealtimeServerEventResponseAudioDone( - RealtimeServerEvent, discriminator="response.output_audio.done" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when the model-generated audio is done. Also emitted when a Response is interrupted, - incomplete, or cancelled. +class Metadata(_Model): + """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. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_audio.done``. Required. - RESPONSE_OUTPUT_AUDIO_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_DONE - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_audio.done``. Required. RESPONSE_OUTPUT_AUDIO_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" + +class Microsoft365PermissionScopes(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A set of delegated permission scopes requested from a single resource application. + + :ivar resource_app_id: Application id of the resource that exposes the requested delegated + scopes. Required. + :vartype resource_app_id: str + :ivar scopes: Delegated scope names requested from the resource application. Must not be empty. + Required. + :vartype scopes: list[str] + """ + + resource_app_id: str = rest_field(name="resourceAppId", visibility=["read", "create", "update", "delete", "query"]) + """Application id of the resource that exposes the requested delegated scopes. Required.""" + scopes: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Delegated scope names requested from the resource application. Must not be empty. Required.""" @overload def __init__( self, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, + resource_app_id: str, + scopes: list[str], ) -> None: ... @overload @@ -20529,57 +21411,125 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DONE # type: ignore -class RealtimeServerEventResponseAudioTranscriptDelta( - RealtimeServerEvent, discriminator="response.output_audio_transcript.delta" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the model-generated transcription of audio output is updated. +class Microsoft365PublishDefaults(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Default and previously-published values used to pre-populate a Microsoft 365 publish request + for a Foundry agent. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_audio_transcript.delta``. Required. - RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar delta: The transcript delta. Required. - :vartype delta: str + :ivar app_publish_scope: The publish scope. Known values are: "Personal", "Shared", and + "Tenant". + :vartype app_publish_scope: str or ~azure.ai.projects.models.Microsoft365PublishScope + :ivar agent_name: The agent name. + :vartype agent_name: str + :ivar agent_display_name: The user-facing display name for the agent. Defaults to the agent + name if not previously overridden. + :vartype agent_display_name: str + :ivar app_registration_client_id: The app-registration client id associated with the agent. + :vartype app_registration_client_id: str + :ivar bot_service_arm_id: ARM resource id of the Azure Bot Service associated with the + previously-published app, if any. + :vartype bot_service_arm_id: str + :ivar app_version: The most recently published app version. + :vartype app_version: str + :ivar recommended_next_app_version: The recommended next app version (the most recent app + version, incremented). + :vartype recommended_next_app_version: str + :ivar title_id: The Microsoft 365 title id of the previously-published app, if any. + :vartype title_id: str + :ivar teams_app_id: The Microsoft Teams app id of the previously-published app, if any. + :vartype teams_app_id: str + :ivar short_description: Short, one-line description shown in the Teams app listing. + :vartype short_description: str + :ivar full_description: Full description shown on the Teams app details page. + :vartype full_description: str + :ivar developer_name: Display name of the developer / publisher. + :vartype developer_name: str + :ivar developer_website_url: Developer / publisher website URL. + :vartype developer_website_url: str + :ivar privacy_url: Privacy policy URL. + :vartype privacy_url: str + :ivar terms_of_use_url: Terms-of-use URL. + :vartype terms_of_use_url: str """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_audio_transcript.delta``. Required. - RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The transcript delta. Required.""" + app_publish_scope: Optional[Union[str, "_models.Microsoft365PublishScope"]] = rest_field( + name="appPublishScope", visibility=["read", "create", "update", "delete", "query"] + ) + """The publish scope. Known values are: \"Personal\", \"Shared\", and \"Tenant\".""" + agent_name: Optional[str] = rest_field(name="agentName", visibility=["read", "create", "update", "delete", "query"]) + """The agent name.""" + agent_display_name: Optional[str] = rest_field( + name="agentDisplayName", visibility=["read", "create", "update", "delete", "query"] + ) + """The user-facing display name for the agent. Defaults to the agent name if not previously + overridden.""" + app_registration_client_id: Optional[str] = rest_field( + name="appRegistrationClientId", visibility=["read", "create", "update", "delete", "query"] + ) + """The app-registration client id associated with the agent.""" + bot_service_arm_id: Optional[str] = rest_field( + name="botServiceArmId", visibility=["read", "create", "update", "delete", "query"] + ) + """ARM resource id of the Azure Bot Service associated with the previously-published app, if any.""" + app_version: Optional[str] = rest_field( + name="appVersion", visibility=["read", "create", "update", "delete", "query"] + ) + """The most recently published app version.""" + recommended_next_app_version: Optional[str] = rest_field( + name="recommendedNextAppVersion", visibility=["read", "create", "update", "delete", "query"] + ) + """The recommended next app version (the most recent app version, incremented).""" + title_id: Optional[str] = rest_field(name="titleId", visibility=["read", "create", "update", "delete", "query"]) + """The Microsoft 365 title id of the previously-published app, if any.""" + teams_app_id: Optional[str] = rest_field( + name="teamsAppId", visibility=["read", "create", "update", "delete", "query"] + ) + """The Microsoft Teams app id of the previously-published app, if any.""" + short_description: Optional[str] = rest_field( + name="shortDescription", visibility=["read", "create", "update", "delete", "query"] + ) + """Short, one-line description shown in the Teams app listing.""" + full_description: Optional[str] = rest_field( + name="fullDescription", visibility=["read", "create", "update", "delete", "query"] + ) + """Full description shown on the Teams app details page.""" + developer_name: Optional[str] = rest_field( + name="developerName", visibility=["read", "create", "update", "delete", "query"] + ) + """Display name of the developer / publisher.""" + developer_website_url: Optional[str] = rest_field( + name="developerWebsiteUrl", visibility=["read", "create", "update", "delete", "query"] + ) + """Developer / publisher website URL.""" + privacy_url: Optional[str] = rest_field( + name="privacyUrl", visibility=["read", "create", "update", "delete", "query"] + ) + """Privacy policy URL.""" + terms_of_use_url: Optional[str] = rest_field( + name="termsOfUseUrl", visibility=["read", "create", "update", "delete", "query"] + ) + """Terms-of-use URL.""" @overload def __init__( self, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - delta: str, + app_publish_scope: Optional[Union[str, "_models.Microsoft365PublishScope"]] = None, + agent_name: Optional[str] = None, + agent_display_name: Optional[str] = None, + app_registration_client_id: Optional[str] = None, + bot_service_arm_id: Optional[str] = None, + app_version: Optional[str] = None, + recommended_next_app_version: Optional[str] = None, + title_id: Optional[str] = None, + teams_app_id: Optional[str] = None, + short_description: Optional[str] = None, + full_description: Optional[str] = None, + developer_name: Optional[str] = None, + developer_website_url: Optional[str] = None, + privacy_url: Optional[str] = None, + terms_of_use_url: Optional[str] = None, ) -> None: ... @overload @@ -20591,58 +21541,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA # type: ignore -class RealtimeServerEventResponseAudioTranscriptDone( - RealtimeServerEvent, discriminator="response.output_audio_transcript.done" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the model-generated transcription of audio output is done streaming. Also emitted - when a Response is interrupted, incomplete, or cancelled. +class Microsoft365PublishResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Response from publishing an agent to Microsoft 365 / Microsoft Teams. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_audio_transcript.done``. Required. - RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar transcript: The final transcript of the audio. Required. - :vartype transcript: str + :ivar title_id: The Microsoft 365 title id of the published app. + :vartype title_id: str + :ivar teams_app_id: The Microsoft Teams app id of the published app. + :vartype teams_app_id: str """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_audio_transcript.done``. Required. - RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - transcript: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The final transcript of the audio. Required.""" + title_id: Optional[str] = rest_field(name="titleId", visibility=["read", "create", "update", "delete", "query"]) + """The Microsoft 365 title id of the published app.""" + teams_app_id: Optional[str] = rest_field( + name="teamsAppId", visibility=["read", "create", "update", "delete", "query"] + ) + """The Microsoft Teams app id of the published app.""" @overload def __init__( self, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - transcript: str, + title_id: Optional[str] = None, + teams_app_id: Optional[str] = None, ) -> None: ... @overload @@ -20654,59 +21576,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE # type: ignore -class RealtimeServerEventResponseContentPartAdded( - RealtimeServerEvent, discriminator="response.content_part.added" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when a new content part is added to an assistant message item during response - generation. +class MicrosoftCopilotHarness(AgentHarness, discriminator="microsoft_copilot_preview"): + """The Microsoft Copilot managed harness for prompt agents. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.content_part.added``. Required. - RESPONSE_CONTENT_PART_ADDED. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_CONTENT_PART_ADDED - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item to which the content part was added. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar part: The content part that was added. Required. - :vartype part: ~azure.ai.projects.models.RealtimeServerEventResponseContentPartAddedPart + :ivar type: The type of managed harness. Always ``microsoft_copilot_preview``. Required. + Default value is "microsoft_copilot_preview". + :vartype type: str """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_ADDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.content_part.added``. Required. RESPONSE_CONTENT_PART_ADDED.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item to which the content part was added. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - part: "_models.RealtimeServerEventResponseContentPartAddedPart" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The content part that was added. Required.""" + type: Literal["microsoft_copilot_preview"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of managed harness. Always ``microsoft_copilot_preview``. Required. Default value is + \"microsoft_copilot_preview\".""" @overload def __init__( self, - *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - part: "_models.RealtimeServerEventResponseContentPartAddedPart", ) -> None: ... @overload @@ -20718,38 +21604,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_CONTENT_PART_ADDED # type: ignore + self.type = "microsoft_copilot_preview" # type: ignore -class RealtimeServerEventResponseContentPartAddedPart( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeServerEventResponseContentPartAddedPart. +class MicrosoftCopilotToolsetConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An enablement override for a Microsoft Copilot built-in tool. - :ivar type: Is either a Literal["audio"] type or a Literal["text"] type. - :vartype type: str or str - :ivar text: - :vartype text: str - :ivar audio: - :vartype audio: str - :ivar transcript: - :vartype transcript: str + :ivar name: The built-in tool to configure. Required. Known values are: "filesystem_read", + "filesystem_write", "shell", "web", and "subagents". + :vartype name: str or ~azure.ai.projects.models.MicrosoftCopilotBuiltInTool + :ivar enabled: Whether the built-in tool is enabled. If omitted, the toolset default applies. + :vartype enabled: bool """ - type: Optional[Literal["audio", "text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Is either a Literal[\"audio\"] type or a Literal[\"text\"] type.""" - text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + name: Union[str, "_models.MicrosoftCopilotBuiltInTool"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The built-in tool to configure. Required. Known values are: \"filesystem_read\", + \"filesystem_write\", \"shell\", \"web\", and \"subagents\".""" + enabled: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the built-in tool is enabled. If omitted, the toolset default applies.""" @overload def __init__( self, *, - type: Optional[Literal["audio", "text"]] = None, - text: Optional[str] = None, - audio: Optional[str] = None, - transcript: Optional[str] = None, + name: Union[str, "_models.MicrosoftCopilotBuiltInTool"], + enabled: Optional[bool] = None, ) -> None: ... @overload @@ -20763,56 +21644,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RealtimeServerEventResponseContentPartDone( - RealtimeServerEvent, discriminator="response.content_part.done" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when a content part is done streaming in an assistant message item. Also emitted when - a Response is interrupted, incomplete, or cancelled. - - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.content_part.done``. Required. - RESPONSE_CONTENT_PART_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_CONTENT_PART_DONE - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar part: The content part that is done. Required. - :vartype part: ~azure.ai.projects.models.RealtimeServerEventResponseContentPartDonePart +class MicrosoftCopilotToolsetDefaultConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The default enablement setting for Microsoft Copilot built-in tools. + + :ivar enabled: Whether built-in tools are enabled by default. Defaults to true. + :vartype enabled: bool """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.content_part.done``. Required. RESPONSE_CONTENT_PART_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - part: "_models.RealtimeServerEventResponseContentPartDonePart" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The content part that is done. Required.""" + enabled: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether built-in tools are enabled by default. Defaults to true.""" @overload def __init__( self, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - part: "_models.RealtimeServerEventResponseContentPartDonePart", + enabled: Optional[bool] = None, ) -> None: ... @overload @@ -20824,45 +21670,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_CONTENT_PART_DONE # type: ignore -class RealtimeServerEventResponseContentPartDonePart( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """RealtimeServerEventResponseContentPartDonePart. +class MicrosoftCopilotToolsetPreview( + Tool, discriminator="microsoft_copilot_toolset_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration overrides for Microsoft Copilot built-in tools. - :ivar type: Is either a Literal["audio"] type or a Literal["text"] type. - :vartype type: str or str - :ivar text: - :vartype text: str - :ivar audio: - :vartype audio: str - :ivar transcript: - :vartype transcript: str - :ivar format: The audio format, when this is an audio content part. - :vartype format: ~azure.ai.projects.models.RealtimeAudioFormats + :ivar type: The type of the toolset. Always ``microsoft_copilot_toolset_preview``. Required. + MICROSOFT_COPILOT_TOOLSET_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.MICROSOFT_COPILOT_TOOLSET_PREVIEW + :ivar default_config: The default configuration for built-in tools. If omitted, built-in tools + are enabled by default. + :vartype default_config: ~azure.ai.projects.models.MicrosoftCopilotToolsetDefaultConfig + :ivar configs: Per-tool configuration overrides. Duplicate built-in tool names are not allowed. + :vartype configs: list[~azure.ai.projects.models.MicrosoftCopilotToolsetConfig] """ - type: Optional[Literal["audio", "text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Is either a Literal[\"audio\"] type or a Literal[\"text\"] type.""" - text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - format: Optional["_models.RealtimeAudioFormats"] = rest_field( + type: Literal[ToolType.MICROSOFT_COPILOT_TOOLSET_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the toolset. Always ``microsoft_copilot_toolset_preview``. Required. + MICROSOFT_COPILOT_TOOLSET_PREVIEW.""" + default_config: Optional["_models.MicrosoftCopilotToolsetDefaultConfig"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The audio format, when this is an audio content part.""" + """The default configuration for built-in tools. If omitted, built-in tools are enabled by + default.""" + configs: Optional[list["_models.MicrosoftCopilotToolsetConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-tool configuration overrides. Duplicate built-in tool names are not allowed.""" @overload def __init__( self, *, - type: Optional[Literal["audio", "text"]] = None, - text: Optional[str] = None, - audio: Optional[str] = None, - transcript: Optional[str] = None, - format: Optional["_models.RealtimeAudioFormats"] = None, + default_config: Optional["_models.MicrosoftCopilotToolsetDefaultConfig"] = None, + configs: Optional[list["_models.MicrosoftCopilotToolsetConfig"]] = None, ) -> None: ... @overload @@ -20874,37 +21717,34 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = ToolType.MICROSOFT_COPILOT_TOOLSET_PREVIEW # type: ignore -class RealtimeServerEventResponseCreated( - RealtimeServerEvent, discriminator="response.created" +class MicrosoftFabricPreviewTool( + Tool, discriminator="fabric_dataagent_preview" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when a new Response is created. The first event of response creation, where the - response is in an initial state of ``in_progress``. + """The input definition information for a Microsoft Fabric tool as used to configure an agent. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.created``. Required. RESPONSE_CREATED. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_CREATED - :ivar response: Required. - :vartype response: ~azure.ai.projects.models.VoiceAgentRealtimeResponse + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.created``. Required. RESPONSE_CREATED.""" - response: "_models.VoiceAgentRealtimeResponse" = rest_field( + 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"] ) - """Required.""" + """The fabric data agent tool parameters. Required.""" @overload def __init__( self, *, - event_id: str, - response: "_models.VoiceAgentRealtimeResponse", + fabric_dataagent_preview: "_models.FabricDataAgentToolParameters", ) -> None: ... @overload @@ -20916,42 +21756,46 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_CREATED # type: ignore + self.type = ToolType.FABRIC_DATAAGENT_PREVIEW # type: ignore -class RealtimeServerEventResponseDone( - RealtimeServerEvent, discriminator="response.done" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when a Response is done streaming. Always emitted, no matter the final state. The - Response object included in the ``response.done`` event will include all output Items in the - Response but will omit the raw audio data. Clients should check the ``status`` field of the - Response to determine if it was successful (``completed``) or if there was another outcome: - ``cancelled``, ``failed``, or ``incomplete``. A response will contain all output items that - were generated during the response, excluding any audio content. +class MisalignmentErrorDetailsResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """MisalignmentErrorDetailsResource. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.done``. Required. RESPONSE_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_DONE - :ivar response: Required. - :vartype response: ~azure.ai.projects.models.VoiceAgentRealtimeResponse + :ivar review_target: + :vartype review_target: str + :ivar error_type: An optional classification; clients must accept additional values. Known + values are: "potentially_unintended_data_transfer", "potentially_unintended_data_access", + "potentially_unintended_destructive_activity", and "other". + :vartype error_type: str or ~azure.ai.projects.models.MisalignmentErrorType + :ivar detailed_explanation: The public explanation for this block. + :vartype detailed_explanation: str + :ivar steer: An optional public continuation instruction. + :vartype steer: ~azure.ai.projects.models.MisalignmentSteer """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.done``. Required. RESPONSE_DONE.""" - response: "_models.VoiceAgentRealtimeResponse" = rest_field( + review_target: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + error_type: Optional[Union[str, "_models.MisalignmentErrorType"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Required.""" + """An optional classification; clients must accept additional values. Known values are: + \"potentially_unintended_data_transfer\", \"potentially_unintended_data_access\", + \"potentially_unintended_destructive_activity\", and \"other\".""" + detailed_explanation: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The public explanation for this block.""" + steer: Optional["_models.MisalignmentSteer"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """An optional public continuation instruction.""" @overload def __init__( self, *, - event_id: str, - response: "_models.VoiceAgentRealtimeResponse", + review_target: Optional[str] = None, + error_type: Optional[Union[str, "_models.MisalignmentErrorType"]] = None, + detailed_explanation: Optional[str] = None, + steer: Optional["_models.MisalignmentSteer"] = None, ) -> None: ... @overload @@ -20963,57 +21807,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_DONE # type: ignore -class RealtimeServerEventResponseFunctionCallArgumentsDelta( - RealtimeServerEvent, discriminator="response.function_call_arguments.delta" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the model-generated function call arguments are updated. +class MisalignmentSteer(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """MisalignmentSteer. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.function_call_arguments.delta``. Required. - RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the function call item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar call_id: The ID of the function call. Required. - :vartype call_id: str - :ivar delta: The arguments delta as a JSON string. Required. - :vartype delta: str + :ivar message: The public continuation instruction. Required. + :vartype message: str """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.function_call_arguments.delta``. Required. - RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the function call item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the function call. Required.""" - delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The arguments delta as a JSON string. Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The public continuation instruction. Required.""" @overload def __init__( self, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - call_id: str, - delta: str, + message: str, ) -> None: ... @overload @@ -21025,63 +21835,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA # type: ignore -class RealtimeServerEventResponseFunctionCallArgumentsDone( - RealtimeServerEvent, discriminator="response.function_call_arguments.done" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when the model-generated function call arguments are done streaming. Also emitted when - a Response is interrupted, incomplete, or cancelled. +class ModelCredentialRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Request to fetch credentials for a model asset. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.function_call_arguments.done``. Required. - RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the function call item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar call_id: The ID of the function call. Required. - :vartype call_id: str - :ivar name: The name of the function that was called. Required. - :vartype name: str - :ivar arguments: The final arguments as a JSON string. Required. - :vartype arguments: str + :ivar blob_uri: Blob URI of the model asset to fetch credentials for. Required. + :vartype blob_uri: str """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.function_call_arguments.done``. Required. - RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the function call item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the function call. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function that was called. Required.""" - arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The final arguments as a JSON string. Required.""" + 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, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - call_id: str, - name: str, - arguments: str, + blob_uri: str, ) -> None: ... @overload @@ -21093,56 +21863,47 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE # type: ignore -class RealtimeServerEventResponseMCPCallArgumentsDelta( - RealtimeServerEvent, discriminator="response.mcp_call_arguments.delta" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when MCP tool call arguments are updated during response generation. +class ModelDeployment(Deployment, discriminator="ModelDeployment"): + """Model Deployment Definition. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.mcp_call_arguments.delta``. Required. - RESPONSE_MCP_CALL_ARGUMENTS_DELTA. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_ARGUMENTS_DELTA - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the MCP tool call item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar delta: The JSON-encoded arguments delta. Required. - :vartype delta: str - :ivar obfuscation: - :vartype obfuscation: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.mcp_call_arguments.delta``. Required. - RESPONSE_MCP_CALL_ARGUMENTS_DELTA.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP tool call item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The JSON-encoded arguments delta. Required.""" - obfuscation: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + 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, - *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - delta: str, - obfuscation: Optional[str] = None, ) -> None: ... @overload @@ -21154,52 +21915,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DELTA # type: ignore + self.type = DeploymentType.MODEL_DEPLOYMENT # type: ignore -class RealtimeServerEventResponseMCPCallArgumentsDone( - RealtimeServerEvent, discriminator="response.mcp_call_arguments.done" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when MCP tool call arguments are finalized during response generation. +class ModelDeploymentSku(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Sku information. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.mcp_call_arguments.done``. Required. - RESPONSE_MCP_CALL_ARGUMENTS_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_ARGUMENTS_DONE - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the MCP tool call item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar arguments: The final JSON-encoded arguments string. Required. - :vartype arguments: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.mcp_call_arguments.done``. Required. - RESPONSE_MCP_CALL_ARGUMENTS_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP tool call item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The final JSON-encoded arguments string. Required.""" + 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, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - arguments: str, + capacity: int, + family: str, + name: str, + size: str, + tier: str, ) -> None: ... @overload @@ -21211,41 +21964,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DONE # type: ignore -class RealtimeServerEventResponseMCPCallCompleted( - RealtimeServerEvent, discriminator="response.mcp_call.completed" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an MCP tool call has completed successfully. +class ModelPendingUploadRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Represents a request for a pending upload of a model version. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.mcp_call.completed``. Required. - RESPONSE_MCP_CALL_COMPLETED. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_COMPLETED - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar item_id: The ID of the MCP tool call item. Required. - :vartype item_id: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.mcp_call.completed``. Required. RESPONSE_MCP_CALL_COMPLETED.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP tool call item. 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, *, - event_id: str, - output_index: int, - item_id: str, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + pending_upload_id: Optional[str] = None, + connection_name: Optional[str] = None, ) -> None: ... @overload @@ -21257,88 +22011,47 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_MCP_CALL_COMPLETED # type: ignore -class RealtimeServerEventResponseMCPCallFailed( - RealtimeServerEvent, discriminator="response.mcp_call.failed" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when an MCP tool call has failed. +class ModelPendingUploadResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Represents the response for a model pending upload request. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.mcp_call.failed``. Required. - RESPONSE_MCP_CALL_FAILED. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_FAILED - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar item_id: The ID of the MCP tool call item. Required. - :vartype item_id: str + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.mcp_call.failed``. Required. RESPONSE_MCP_CALL_FAILED.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP tool call item. Required.""" - - @overload - def __init__( - self, - *, - event_id: str, - output_index: int, - item_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 = RealtimeServerEventType.RESPONSE_MCP_CALL_FAILED # type: ignore - - -class RealtimeServerEventResponseMCPCallInProgress( - RealtimeServerEvent, discriminator="response.mcp_call.in_progress" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an MCP tool call has started and is in progress. - - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.mcp_call.in_progress``. Required. - RESPONSE_MCP_CALL_IN_PROGRESS. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_IN_PROGRESS - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar item_id: The ID of the MCP tool call item. Required. - :vartype item_id: str - """ - - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_IN_PROGRESS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.mcp_call.in_progress``. Required. - RESPONSE_MCP_CALL_IN_PROGRESS.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the MCP tool call item. Required.""" + blob_reference: "_models.BlobReference" = rest_field( + name="blobReference", visibility=["read", "create", "update", "delete", "query"] + ) + """Container-level read, write, list SAS. Required.""" + pending_upload_id: str = rest_field( + name="pendingUploadId", visibility=["read", "create", "update", "delete", "query"] + ) + """ID for this upload request. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Version of asset to be created if user did not specify version when initially creating upload.""" + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( + name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + ) + """The type of pending upload. Only TemporaryBlobReference is supported for models. Required. + Temporary blob reference.""" @overload def __init__( self, *, - event_id: str, - output_index: int, - item_id: str, + blob_reference: "_models.BlobReference", + pending_upload_id: str, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + version: Optional[str] = None, ) -> None: ... @overload @@ -21350,46 +22063,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_MCP_CALL_IN_PROGRESS # type: ignore -class RealtimeServerEventResponseOutputItemAdded( - RealtimeServerEvent, discriminator="response.output_item.added" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when a new Item is created during Response generation. +class ModelSamplingParams(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Represents a set of parameters used to control the sampling behavior of a language model during + text generation. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_item.added``. Required. - RESPONSE_OUTPUT_ITEM_ADDED. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_ITEM_ADDED - :ivar response_id: The ID of the Response to which the item belongs. Required. - :vartype response_id: str - :ivar output_index: The index of the output item in the Response. Required. - :vartype output_index: int - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_ADDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_item.added``. Required. RESPONSE_OUTPUT_ITEM_ADDED.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the Response to which the item belongs. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the Response. Required.""" - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + 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, *, - event_id: str, - response_id: str, - output_index: int, - item: "_models.RealtimeConversationItem", + temperature: Optional[float] = None, + top_p: Optional[float] = None, + seed: Optional[int] = None, + max_completion_tokens: Optional[int] = None, ) -> None: ... @overload @@ -21401,47 +22107,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_ADDED # type: ignore -class RealtimeServerEventResponseOutputItemDone( - RealtimeServerEvent, discriminator="response.output_item.done" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Returned when an Item is done streaming. Also emitted when a Response is interrupted, - incomplete, or cancelled. +class ModelSourceData(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Source information for the model. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_item.done``. Required. - RESPONSE_OUTPUT_ITEM_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_ITEM_DONE - :ivar response_id: The ID of the Response to which the item belongs. Required. - :vartype response_id: str - :ivar output_index: The index of the output item in the Response. Required. - :vartype output_index: int - :ivar item: Required. - :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + :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 """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_item.done``. Required. RESPONSE_OUTPUT_ITEM_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the Response to which the item belongs. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the Response. Required.""" - item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = rest_field( + name="sourceType", visibility=["read", "create", "update", "delete", "query"] + ) + """The source type of the model. Known values are: \"LocalUpload\" and \"TrainingJob\".""" + job_id: Optional[str] = rest_field(name="jobId", visibility=["read", "create", "update", "delete", "query"]) + """The job ID that produced this model.""" @overload def __init__( self, *, - event_id: str, - response_id: str, - output_index: int, - item: "_models.RealtimeConversationItem", + source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = None, + job_id: Optional[str] = None, ) -> None: ... @overload @@ -21453,56 +22143,80 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_DONE # type: ignore -class RealtimeServerEventResponseTextDelta( - RealtimeServerEvent, discriminator="response.output_text.delta" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when the text value of an "output_text" content part is updated. +class ModelVersion(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Model Version Definition. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_text.delta``. Required. - RESPONSE_OUTPUT_TEXT_DELTA. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_TEXT_DELTA - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar delta: The text delta. Required. - :vartype delta: str + :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] """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_text.delta``. Required. RESPONSE_OUTPUT_TEXT_DELTA.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The text delta. Required.""" + 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, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - delta: str, + 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 @@ -21514,57 +22228,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DELTA # type: ignore -class RealtimeServerEventResponseTextDone( - RealtimeServerEvent, discriminator="response.output_text.done" +class MonthlyRecurrenceSchedule( + RecurrenceSchedule, discriminator="Monthly" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when the text value of an "output_text" content part is done streaming. Also emitted - when a Response is interrupted, incomplete, or cancelled. + """Monthly recurrence schedule. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``response.output_text.done``. Required. - RESPONSE_OUTPUT_TEXT_DONE. - :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_TEXT_DONE - :ivar response_id: The ID of the response. Required. - :vartype response_id: str - :ivar item_id: The ID of the item. Required. - :vartype item_id: str - :ivar output_index: The index of the output item in the response. Required. - :vartype output_index: int - :ivar content_index: The index of the content part in the item's content array. Required. - :vartype content_index: int - :ivar text: The final text content. Required. - :vartype text: str + :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] """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``response.output_text.done``. Required. RESPONSE_OUTPUT_TEXT_DONE.""" - response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the response. Required.""" - item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the item. Required.""" - output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the output item in the response. Required.""" - content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The index of the content part in the item's content array. Required.""" - text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The final text content. 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, *, - event_id: str, - response_id: str, - item_id: str, - output_index: int, - content_index: int, - text: str, + days_of_month: list[int], ) -> None: ... @overload @@ -21576,47 +22264,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DONE # type: ignore + self.type = RecurrenceType.MONTHLY # type: ignore -class RealtimeServerEventSessionCreated( - RealtimeServerEvent, discriminator="session.created" +class NamespaceToolParam( + Tool, discriminator="namespace" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when a Session is created. Emitted automatically when a new connection is established - as the first server event. This event will contain the default Session configuration. + """Namespace. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``session.created``. Required. SESSION_CREATED. - :vartype type: str or ~azure.ai.projects.models.SESSION_CREATED - :ivar session: The session configuration. Required. Is one of the following types: - VoiceAgentSessionResponseConfig - :vartype session: ~azure.ai.projects.models.VoiceAgentSessionResponseConfig - :ivar conversation_id: The session-scoped conversation id. When present, responses attached to - the session conversation use the same value in ``response.created`` and ``response.done``. - :vartype conversation_id: str + :ivar type: The type of the tool. Always ``namespace``. Required. NAMESPACE. + :vartype type: str or ~azure.ai.projects.models.NAMESPACE + :ivar name: The namespace name used in tool calls (for example, ``crm``). Required. + :vartype name: str + :ivar description: A description of the namespace shown to the model. Required. + :vartype description: str + :ivar tools: The function/custom tools available inside this namespace. Required. + :vartype tools: list[~azure.ai.projects.models.FunctionToolParam or + ~azure.ai.projects.models.CustomToolParam] """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.SESSION_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``session.created``. Required. SESSION_CREATED.""" - session: "_unions.VoiceAgentSessionResponse" = rest_field( + type: Literal[ToolType.NAMESPACE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``namespace``. Required. NAMESPACE.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The namespace name used in tool calls (for example, ``crm``). Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description of the namespace shown to the model. Required.""" + tools: list[Union["_models.FunctionToolParam", "_models.CustomToolParam"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The session configuration. Required. Is one of the following types: - VoiceAgentSessionResponseConfig""" - conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The session-scoped conversation id. When present, responses attached to the session - conversation use the same value in ``response.created`` and ``response.done``.""" + """The function/custom tools available inside this namespace. Required.""" @overload def __init__( self, *, - event_id: str, - session: "_unions.VoiceAgentSessionResponse", - conversation_id: Optional[str] = None, + name: str, + description: str, + tools: list[Union["_models.FunctionToolParam", "_models.CustomToolParam"]], ) -> None: ... @overload @@ -21628,39 +22312,22 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_CREATED # type: ignore + self.type = ToolType.NAMESPACE # type: ignore -class RealtimeServerEventSessionUpdated( - RealtimeServerEvent, discriminator="session.updated" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Returned when a session is updated with a ``session.update`` event, unless there is an error. +class NoAuthenticationCredentials(BaseCredentials, discriminator="None"): + """Credentials that do not require authentication. - :ivar event_id: The unique ID of the server event. Required. - :vartype event_id: str - :ivar type: The event type, must be ``session.updated``. Required. SESSION_UPDATED. - :vartype type: str or ~azure.ai.projects.models.SESSION_UPDATED - :ivar session: The session configuration. Required. Is one of the following types: - VoiceAgentSessionResponseConfig - :vartype session: ~azure.ai.projects.models.VoiceAgentSessionResponseConfig + :ivar type: The credential type. Required. No credential. + :vartype type: str or ~azure.ai.projects.models.NONE """ - event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique ID of the server event. Required.""" - type: Literal[RealtimeServerEventType.SESSION_UPDATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type, must be ``session.updated``. Required. SESSION_UPDATED.""" - session: "_unions.VoiceAgentSessionResponse" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The session configuration. Required. Is one of the following types: - VoiceAgentSessionResponseConfig""" + type: Literal[CredentialType.NONE] = rest_discriminator(name="type", visibility=["read"]) # type: ignore + """The credential type. Required. No credential.""" @overload def __init__( self, - *, - event_id: str, - session: "_unions.VoiceAgentSessionResponse", ) -> None: ... @overload @@ -21672,60 +22339,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_UPDATED # type: ignore + self.type = CredentialType.NONE # type: ignore -class Reasoning(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Reasoning. +class OneTimeTrigger(Trigger, discriminator="OneTime"): # pylint: disable=docstring-keyword-should-match-keyword-only + """One-time trigger. - :ivar mode: Controls the reasoning execution mode for the request. When returned on a response, - this is the effective execution mode. Known values are: "standard" and "pro". - :vartype mode: str or ~azure.ai.projects.models.ReasoningModeEnum - :ivar effort: Known values are: "none", "minimal", "low", "medium", "high", "xhigh", and "max". - :vartype effort: str or ~azure.ai.projects.models.ReasoningEffort - :ivar summary: Is one of the following types: Literal["auto"], Literal["concise"], - Literal["detailed"] - :vartype summary: str or str or str - :ivar context: Is one of the following types: Literal["auto"], Literal["current_turn"], - Literal["all_turns"] - :vartype context: str or str or str - :ivar generate_summary: Is one of the following types: Literal["auto"], Literal["concise"], - Literal["detailed"] - :vartype generate_summary: str or str or str + :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 """ - mode: Optional[Union[str, "_models.ReasoningModeEnum"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Controls the reasoning execution mode for the request. When returned on a response, this is the - effective execution mode. Known values are: \"standard\" and \"pro\".""" - effort: Optional[Union[str, "_models.ReasoningEffort"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Known values are: \"none\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", and \"max\".""" - summary: Optional[Literal["auto", "concise", "detailed"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is one of the following types: Literal[\"auto\"], Literal[\"concise\"], Literal[\"detailed\"]""" - context: Optional[Literal["auto", "current_turn", "all_turns"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Is one of the following types: Literal[\"auto\"], Literal[\"current_turn\"], - Literal[\"all_turns\"]""" - generate_summary: Optional[Literal["auto", "concise", "detailed"]] = 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" ) - """Is one of the following types: Literal[\"auto\"], Literal[\"concise\"], Literal[\"detailed\"]""" + """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, *, - mode: Optional[Union[str, "_models.ReasoningModeEnum"]] = None, - effort: Optional[Union[str, "_models.ReasoningEffort"]] = None, - summary: Optional[Literal["auto", "concise", "detailed"]] = None, - context: Optional[Literal["auto", "current_turn", "all_turns"]] = None, - generate_summary: Optional[Literal["auto", "concise", "detailed"]] = None, + trigger_at: datetime.datetime, + time_zone: Optional[str] = None, ) -> None: ... @overload @@ -21737,53 +22379,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 RecurrenceTrigger( - Trigger, discriminator="Recurrence" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Recurrence based trigger. +class OpenApiAuthDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """authentication details for OpenApiFunctionDefinition. - :ivar type: Type of the trigger. Required. Recurrence based trigger. - :vartype type: str or ~azure.ai.projects.models.RECURRENCE - :ivar start_time: Start time for the recurrence schedule in ISO 8601 format. - :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. Defaults to ``UTC``. - :vartype time_zone: str - :ivar interval: Interval for the recurrence schedule. Required. - :vartype interval: int - :ivar schedule: Recurrence schedule for the recurrence trigger. Required. - :vartype schedule: ~azure.ai.projects.models.RecurrenceSchedule + 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[TriggerType.RECURRENCE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Type of the trigger. Required. Recurrence based trigger.""" - start_time: Optional[datetime.datetime] = rest_field( - name="startTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" - ) - """Start time for the recurrence schedule in ISO 8601 format.""" - end_time: Optional[datetime.datetime] = rest_field( - name="endTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" - ) - """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. 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"]) - """Recurrence schedule for the recurrence trigger. 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, *, - interval: int, - schedule: "_models.RecurrenceSchedule", - start_time: Optional[datetime.datetime] = None, - end_time: Optional[datetime.datetime] = None, - time_zone: Optional[str] = None, + type: str, ) -> None: ... @overload @@ -21795,88 +22414,21 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TriggerType.RECURRENCE # type: ignore -class RedTeam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Red team details. +class OpenApiAnonymousAuthDetails(OpenApiAuthDetails, discriminator="anonymous"): + """Security details for OpenApi anonymous authentication. - :ivar name: Identifier of the red team run. Required. - :vartype name: str - :ivar display_name: Name of the red-team run. - :vartype display_name: str - :ivar num_turns: Number of simulation rounds. - :vartype num_turns: int - :ivar attack_strategies: List of attack strategies or nested lists of attack strategies. - :vartype attack_strategies: list[str or ~azure.ai.projects.models.AttackStrategy] - :ivar simulation_only: Simulation-only or Simulation + Evaluation. If ``true`` the scan outputs - conversation not evaluation result. The service defaults to ``false`` if a value is not - specified by the caller. - :vartype simulation_only: bool - :ivar risk_categories: List of risk categories to generate attack objectives for. - :vartype risk_categories: list[str or ~azure.ai.projects.models.RiskCategory] - :ivar application_scenario: Application scenario for the red team operation, to generate - scenario specific attacks. - :vartype application_scenario: str - :ivar tags: Red team's tags. Unlike properties, tags are fully mutable. - :vartype tags: dict[str, str] - :ivar properties: Red team's properties. Unlike tags, properties are add-only. Once added, a - property cannot be removed. - :vartype properties: dict[str, str] - :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.RedTeamTargetConfig + :ivar type: The object type, which is always 'anonymous'. Required. ANONYMOUS. + :vartype type: str or ~azure.ai.projects.models.ANONYMOUS """ - name: str = rest_field(name="id", visibility=["read"]) - """Identifier of the red team run. Required.""" - display_name: Optional[str] = rest_field( - name="displayName", visibility=["read", "create", "update", "delete", "query"] - ) - """Name of the red-team run.""" - num_turns: Optional[int] = rest_field(name="numTurns", visibility=["read", "create", "update", "delete", "query"]) - """Number of simulation rounds.""" - attack_strategies: Optional[list[Union[str, "_models.AttackStrategy"]]] = rest_field( - name="attackStrategies", visibility=["read", "create", "update", "delete", "query"] - ) - """List of attack strategies or nested lists of attack strategies.""" - simulation_only: Optional[bool] = rest_field( - name="simulationOnly", visibility=["read", "create", "update", "delete", "query"] - ) - """Simulation-only or Simulation + Evaluation. If ``true`` the scan outputs conversation not - evaluation result. The service defaults to ``false`` if a value is not specified by the caller.""" - risk_categories: Optional[list[Union[str, "_models.RiskCategory"]]] = rest_field( - name="riskCategories", visibility=["read", "create", "update", "delete", "query"] - ) - """List of risk categories to generate attack objectives for.""" - application_scenario: Optional[str] = rest_field( - name="applicationScenario", visibility=["read", "create", "update", "delete", "query"] - ) - """Application scenario for the red team operation, to generate scenario specific attacks.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Red team's tags. Unlike properties, tags are fully mutable.""" - properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Red team's properties. Unlike tags, properties are add-only. Once added, a property cannot be - removed.""" - status: Optional[str] = rest_field(visibility=["read"]) - """Status of the red-team. It is set by service and is read-only.""" - target: "_models.RedTeamTargetConfig" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Target configuration for the red-team run. Required.""" + 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__( self, - *, - target: "_models.RedTeamTargetConfig", - display_name: Optional[str] = None, - num_turns: Optional[int] = None, - attack_strategies: Optional[list[Union[str, "_models.AttackStrategy"]]] = None, - simulation_only: Optional[bool] = None, - risk_categories: Optional[list[Union[str, "_models.RiskCategory"]]] = None, - application_scenario: Optional[str] = None, - tags: Optional[dict[str, str]] = None, - properties: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -21888,60 +22440,50 @@ 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 -class ReinforcementFineTuningDataGenerationJob( - DataGenerationJob, discriminator="reinforcement_finetuning_preview" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Reinforcement fine-tuning data generation job resource. This is a preview feature. +class OpenApiFunctionDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The input definition information for an openapi function. - :ivar id: Server-assigned unique identifier. Required. - :vartype id: str - :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 name: The display name of the data generation job. Required. + :ivar name: The name of the function to be called. Required. :vartype name: str - :ivar sources: The sources used for the data generation job. Required. - :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] - :ivar generation_configuration: The generation configuration for the data generation job. - Required. - :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration - :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds - since January 1, 1970). Required. - :vartype created_at: ~datetime.datetime - :ivar finished_at: The timestamp when the job was finished, represented in Unix time (seconds - since January 1, 1970). - :vartype finished_at: ~datetime.datetime - :ivar scenario: The scenario of the data generation job, which is Reinforcement Fine-tuning - preview for this model. Required. Reinforcement Fine-tuning preview scenario. - :vartype scenario: str or ~azure.ai.projects.models.REINFORCEMENT_FINETUNING_PREVIEW - :ivar output_configuration: Optional file output configuration for the generated reinforcement - fine-tuning data. - :vartype output_configuration: - ~azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobOutputConfiguration + :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] """ - scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The scenario of the data generation job, which is Reinforcement Fine-tuning preview for this - model. Required. Reinforcement Fine-tuning preview scenario.""" - output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional file output configuration for the generated reinforcement fine-tuning data.""" + 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.""" @overload def __init__( self, *, name: str, - sources: list["_models.DataGenerationJobSource"], - generation_configuration: "_models.DataGenerationJobConfiguration", - output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = None, + spec: dict[str, Any], + auth: "_models.OpenApiAuthDetails", + description: Optional[str] = None, + default_params: Optional[list[str]] = None, ) -> None: ... @overload @@ -21953,47 +22495,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.scenario = DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW # type: ignore -class ReinforcementFineTuningDataGenerationJobInputs( - DataGenerationJobInputs, discriminator="reinforcement_finetuning_preview" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Caller-supplied inputs for a reinforcement fine-tuning data generation job. This is a preview - feature. +class OpenApiFunctionDefinitionFunction(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """OpenApiFunctionDefinitionFunction. - :ivar name: The display name of the data generation job. Required. + :ivar name: The name of the function to be called. Required. :vartype name: str - :ivar sources: The sources used for the data generation job. Required. - :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] - :ivar generation_configuration: The generation configuration for the data generation job. + :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 generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration - :ivar scenario: The scenario of the data generation job, which is Reinforcement Fine-tuning - preview for this model. Required. Reinforcement Fine-tuning preview scenario. - :vartype scenario: str or ~azure.ai.projects.models.REINFORCEMENT_FINETUNING_PREVIEW - :ivar output_configuration: Optional file output configuration for the generated reinforcement - fine-tuning data. - :vartype output_configuration: - ~azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobOutputConfiguration + :vartype parameters: dict[str, any] """ - scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The scenario of the data generation job, which is Reinforcement Fine-tuning preview for this - model. Required. Reinforcement Fine-tuning preview scenario.""" - output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional file output configuration for the generated reinforcement fine-tuning data.""" + 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, *, name: str, - sources: list["_models.DataGenerationJobSource"], - generation_configuration: "_models.DataGenerationJobConfiguration", - output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = None, + parameters: dict[str, Any], + description: Optional[str] = None, ) -> None: ... @overload @@ -22005,42 +22536,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.scenario = DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW # type: ignore -class ReinforcementFineTuningDataGenerationJobOutputConfiguration( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """File output configuration for a reinforcement fine-tuning data generation job. This is a - preview feature. +class OpenApiManagedAuthDetails( + OpenApiAuthDetails, discriminator="managed_identity" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Security details for OpenApi managed_identity authentication. - :ivar name: Filename to assign to the generated fine-tuning file. Required. - :vartype name: str - :ivar write_mode: Controls how file outputs are written. If omitted, defaults to ``overwrite`` - and writes only the newly generated fine-tuning file content. Known values are: "overwrite" and - "merge". - :vartype write_mode: str or ~azure.ai.projects.models.DataGenerationJobOutputWriteMode - :ivar merge_file_id: File ID to merge into when ``write_mode`` is ``merge``. - :vartype merge_file_id: str + :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 """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Filename to assign to the generated fine-tuning file. Required.""" - write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = rest_field( + 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"] ) - """Controls how file outputs are written. If omitted, defaults to ``overwrite`` and writes only - the newly generated fine-tuning file content. Known values are: \"overwrite\" and \"merge\".""" - merge_file_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """File ID to merge into when ``write_mode`` is ``merge``.""" + """Connection auth security details. Required.""" @overload def __init__( self, *, - name: str, - write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = None, - merge_file_id: Optional[str] = None, + security_scheme: "_models.OpenApiManagedSecurityScheme", ) -> None: ... @overload @@ -22052,35 +22572,24 @@ 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 ReminderPreviewToolboxTool( - ToolboxTool, discriminator="reminder_preview" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A reminder tool stored in a toolbox. +class OpenApiManagedSecurityScheme(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Security scheme for OpenApi managed_identity authentication. - :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 type: Required. REMINDER_PREVIEW. - :vartype type: str or ~azure.ai.projects.models.REMINDER_PREVIEW + :ivar audience: Authentication scope for managed_identity auth type. Required. + :vartype audience: str """ - type: Literal[ToolboxToolType.REMINDER_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. REMINDER_PREVIEW.""" + audience: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Authentication scope for managed_identity auth type. Required.""" @overload def __init__( self, *, - name: Optional[str] = None, - description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + audience: str, ) -> None: ... @overload @@ -22092,33 +22601,61 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolboxToolType.REMINDER_PREVIEW # type: ignore -class ResponsesProtocolConfiguration(_Model): - """Configuration specific to the responses protocol.""" +class OpenApiProjectConnectionAuthDetails( + OpenApiAuthDetails, discriminator="project_connection" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Security details for OpenApi project connection authentication. + :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 + """ -class ResponseUsageInputTokensDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """ResponseUsageInputTokensDetails. + 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"] + ) + """Project connection auth security details. Required.""" - :ivar cached_tokens: Required. - :vartype cached_tokens: int - :ivar cache_write_tokens: Required. - :vartype cache_write_tokens: int + @overload + def __init__( + self, + *, + security_scheme: "_models.OpenApiProjectConnectionSecurityScheme", + ) -> 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 = OpenApiAuthType.PROJECT_CONNECTION # type: ignore + + +class OpenApiProjectConnectionSecurityScheme(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Security scheme for OpenApi managed_identity authentication. + + :ivar project_connection_id: Project connection id for Project Connection auth type. Required. + :vartype project_connection_id: str """ - cached_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - cache_write_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + 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, *, - cached_tokens: int, - cache_write_tokens: int, + project_connection_id: str, ) -> None: ... @overload @@ -22132,21 +22669,35 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ResponseUsageOutputTokensDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """ResponseUsageOutputTokensDetails. +class OpenApiTool(Tool, discriminator="openapi"): # pylint: disable=docstring-keyword-should-match-keyword-only + """The input definition information for an OpenAPI tool as used to configure an agent. - :ivar reasoning_tokens: Required. - :vartype reasoning_tokens: int + :ivar type: The object type, which is always 'openapi'. Required. OPENAPI. + :vartype type: str or ~azure.ai.projects.models.OPENAPI + :ivar tool_configs: Deprecated. This property is deprecated and will be removed in a future + version. + :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] + :ivar openapi: The openapi function definition. Required. + :vartype openapi: ~azure.ai.projects.models.OpenApiFunctionDefinition """ - reasoning_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + 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.""" + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Deprecated. This property is deprecated and will be removed in a future version.""" + openapi: "_models.OpenApiFunctionDefinition" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The openapi function definition. Required.""" @overload def __init__( self, *, - reasoning_tokens: int, + openapi: "_models.OpenApiFunctionDefinition", + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -22158,59 +22709,43 @@ 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 Routine(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A routine definition returned by the service. +class OpenApiToolboxTool( + ToolboxTool, discriminator="openapi" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An OpenAPI tool stored in a toolbox. - :ivar name: The routine name. + :ivar name: Optional user-defined name for this tool or configuration. :vartype name: str - :ivar description: A human-readable description of the routine. + :ivar description: Optional user-defined description for this tool or configuration. :vartype description: str - :ivar enabled: Whether the routine is enabled. Required. - :vartype enabled: bool - :ivar triggers: The triggers configured for the routine. - :vartype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] - :ivar action: The action executed when the routine fires. - :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 + :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 type: 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 """ - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The routine name.""" - 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: Optional[dict[str, "_models.RoutineTrigger"]] = rest_field( + type: Literal[ToolboxToolType.OPENAPI] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. OPENAPI.""" + openapi: "_models.OpenApiFunctionDefinition" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The triggers configured for the routine.""" - action: Optional["_models.RoutineAction"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The action executed when the routine fires.""" - 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.""" + """The openapi function definition. Required.""" @overload def __init__( self, *, - enabled: bool, + openapi: "_models.OpenApiFunctionDefinition", name: Optional[str] = None, description: Optional[str] = None, - triggers: Optional[dict[str, "_models.RoutineTrigger"]] = None, - action: Optional["_models.RoutineAction"] = None, - created_at: Optional[datetime.datetime] = None, - updated_at: Optional[datetime.datetime] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -22222,29 +22757,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = ToolboxToolType.OPENAPI # type: ignore -class RoutineAuthorization(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Optional authorization configuration for a routine dispatch. +class OptimizationContext(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Base model for typed optimization context. - :ivar identity: The identity used when dispatching the routine. Defaults to agent when omitted; - set to creator only when the customer opts in to creator identity dispatch. Known values are: - "agent" and "creator". - :vartype identity: str or ~azure.ai.projects.models.RoutineDispatchIdentity + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + SteeringPromptOptimizationContext + + :ivar type: Optimization context type discriminator. Required. "steering_prompt" + :vartype type: str or ~azure.ai.projects.models.OptimizationContextType """ - identity: Optional[Union[str, "_models.RoutineDispatchIdentity"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The identity used when dispatching the routine. Defaults to agent when omitted; set to creator - only when the customer opts in to creator identity dispatch. Known values are: \"agent\" and - \"creator\".""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Optimization context type discriminator. Required. \"steering_prompt\"""" @overload def __init__( self, *, - identity: Optional[Union[str, "_models.RoutineDispatchIdentity"]] = None, + type: str, ) -> None: ... @overload @@ -22258,162 +22792,40 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RoutineRun(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A single routine run returned from the run history API. +class TelemetryEndpoint(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A telemetry export endpoint configuration. - :ivar id: The unique run identifier for the routine attempt. Required. - :vartype id: str - :ivar status: The run status. Is one of the following types: str - :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. Known values are: - "custom", "github_issue", "schedule", and "timer". - :vartype trigger_type: str or ~azure.ai.projects.models.RoutineTriggerType - :ivar trigger_name: The configured trigger name that produced the routine attempt. - :vartype trigger_name: str - :ivar trigger_event_payload: The event payload captured from the event that triggered the - routine attempt, when available. - :vartype trigger_event_payload: dict[str, any] - :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 agent_id: The project-scoped agent identifier recorded for the routine attempt. - :vartype agent_id: str - :ivar agent_endpoint_id: The legacy endpoint-scoped agent identifier recorded for the routine - attempt. - :vartype agent_endpoint_id: str - :ivar conversation_id: The conversation identifier used by a responses API dispatch. - :vartype conversation_id: str - :ivar session_id: The hosted-agent session identifier used by an invocations API dispatch. - :vartype session_id: str - :ivar triggered_at: The logical trigger time recorded for the routine attempt. - :vartype triggered_at: ~datetime.datetime - :ivar scheduled_fire_at: The scheduled fire time recorded for timer and schedule deliveries. - :vartype scheduled_fire_at: ~datetime.datetime - :ivar started_at: The time when the underlying run started. - :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_status_code: The downstream error status code captured for a failed attempt, when - available. - :vartype error_status_code: int - :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 + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + OtlpTelemetryEndpoint + + :ivar kind: The telemetry export endpoint kind. Required. "OTLP" + :vartype kind: str or ~azure.ai.projects.models.TelemetryEndpointKind + :ivar data: Data types to export to this endpoint. Use an empty array to export no data. + Required. + :vartype data: list[str or ~azure.ai.projects.models.TelemetryDataKind] + :ivar auth: Optional authentication configuration. + :vartype auth: ~azure.ai.projects.models.TelemetryEndpointAuth """ - id: str = rest_field(visibility=["read"]) - """The unique run identifier for the routine attempt. Required.""" - status: Optional["_unions.RoutineRunStatus"] = rest_field( + __mapping__: dict[str, _Model] = {} + kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) + """The telemetry export endpoint kind. Required. \"OTLP\"""" + data: list[Union[str, "_models.TelemetryDataKind"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The run status. Is one of the following types: str""" - phase: Optional[Union[str, "_models.RoutineRunPhase"]] = rest_field( + """Data types to export to this endpoint. Use an empty array to export no data. Required.""" + auth: Optional["_models.TelemetryEndpointAuth"] = 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: Optional[Union[str, "_models.RoutineTriggerType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The trigger type that produced the routine attempt. Known values are: \"custom\", - \"github_issue\", \"schedule\", and \"timer\".""" - trigger_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The configured trigger name that produced the routine attempt.""" - trigger_event_payload: Optional[dict[str, Any]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The event payload captured from the event that triggered the routine attempt, when available.""" - 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\".""" - agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The project-scoped agent identifier recorded for the routine attempt.""" - agent_endpoint_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The legacy endpoint-scoped agent identifier recorded for the routine attempt.""" - conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The conversation identifier used by a responses API dispatch.""" - session_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The hosted-agent session identifier used by an invocations API dispatch.""" - 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.""" - scheduled_fire_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The scheduled fire time recorded for timer and schedule deliveries.""" - started_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The time when the underlying run started.""" - 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_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The downstream error status code captured for a failed 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.""" + """Optional authentication configuration.""" @overload def __init__( self, *, - status: Optional["_unions.RoutineRunStatus"] = None, - phase: Optional[Union[str, "_models.RoutineRunPhase"]] = None, - trigger_type: Optional[Union[str, "_models.RoutineTriggerType"]] = None, - trigger_name: Optional[str] = None, - trigger_event_payload: Optional[dict[str, Any]] = None, - attempt_source: Optional[Union[str, "_models.RoutineAttemptSource"]] = None, - action_type: Optional[Union[str, "_models.RoutineActionType"]] = None, - agent_id: Optional[str] = None, - agent_endpoint_id: Optional[str] = None, - conversation_id: Optional[str] = None, - session_id: Optional[str] = None, - triggered_at: Optional[datetime.datetime] = None, - scheduled_fire_at: Optional[datetime.datetime] = None, - started_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_status_code: Optional[int] = None, - error_type: Optional[str] = None, - error_message: Optional[str] = None, + kind: str, + data: list[Union[str, "_models.TelemetryDataKind"]], + auth: Optional["_models.TelemetryEndpointAuth"] = None, ) -> None: ... @overload @@ -22427,61 +22839,45 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RubricBasedEvaluatorDefinition( - EvaluatorDefinition, discriminator="rubric" +class OtlpTelemetryEndpoint( + TelemetryEndpoint, discriminator="OTLP" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Rubric-based evaluator definition — stores dimensions produced by the generate API. Used for - both quality and safety evaluators. + """An OTLP (OpenTelemetry Protocol) telemetry export endpoint. - :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 + :ivar data: Data types to export to this endpoint. Use an empty array to export no data. + Required. + :vartype data: list[str or ~azure.ai.projects.models.TelemetryDataKind] + :ivar auth: Optional authentication configuration. + :vartype auth: ~azure.ai.projects.models.TelemetryEndpointAuth + :ivar kind: The endpoint kind, always 'OTLP' for OpenTelemetry Protocol endpoints. Required. + OpenTelemetry Protocol (OTLP) endpoint. + :vartype kind: str or ~azure.ai.projects.models.OTLP + :ivar endpoint: The OTLP collector endpoint URL. Required. + :vartype endpoint: str + :ivar protocol: The transport protocol for the OTLP endpoint. Required. Known values are: + "Http" and "Grpc". + :vartype protocol: str or ~azure.ai.projects.models.TelemetryTransportProtocol """ - 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.""" + kind: Literal[TelemetryEndpointKind.OTLP] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The endpoint kind, always 'OTLP' for OpenTelemetry Protocol endpoints. Required. OpenTelemetry + Protocol (OTLP) endpoint.""" + endpoint: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The OTLP collector endpoint URL. Required.""" + protocol: Union[str, "_models.TelemetryTransportProtocol"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The transport protocol for the OTLP endpoint. Required. Known values are: \"Http\" and + \"Grpc\".""" @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, + data: list[Union[str, "_models.TelemetryDataKind"]], + endpoint: str, + protocol: Union[str, "_models.TelemetryTransportProtocol"], + auth: Optional["_models.TelemetryEndpointAuth"] = None, ) -> None: ... @overload @@ -22493,66 +22889,24 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorDefinitionType.RUBRIC # type: ignore + self.kind = TelemetryEndpointKind.OTLP # type: ignore -class RubricGenerationInputQualityWarning(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A non-fatal advisory produced during rubric evaluator generation when resolved inputs are - technically valid but likely too weak to produce a high-quality rubric. Read-only; - service-generated. Persisted with the terminal EvaluatorGenerationJob. +class OutputTokensDetailsResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """OutputTokensDetailsResource. - :ivar code: Stable searchable machine-readable warning code. Required. Known values are: - "empty_prompt", "short_prompt", "empty_agent_instructions", "short_agent_instructions", - "empty_dataset_content", "short_dataset_content", "low_trace_count", and - "insufficient_total_input". - :vartype code: str or ~azure.ai.projects.models.RubricGenerationInputQualityWarningCode - :ivar severity: Advisory severity. Initial values: ``warning``. Required. "warning" - :vartype severity: str or ~azure.ai.projects.models.RubricGenerationInputQualityWarningSeverity - :ivar message: Human-readable message suitable for direct SDK/CLI/UI display. Must not include - raw prompt, instruction, dataset, or trace text. Required. - :vartype message: str - :ivar source: Which source category the warning applies to. ``aggregate`` is used only for - cross-source warnings. Required. Known values are: "prompt", "agent", "dataset", and - "aggregate". - :vartype source: str or ~azure.ai.projects.models.RubricGenerationInputQualityWarningSource - :ivar source_index: Zero-based index into ``EvaluatorGenerationJob.sources`` when the warning - applies to a specific source. Omitted for aggregate warnings and for warnings not tied to one - source. - :vartype source_index: int + :ivar reasoning_tokens: Required. + :vartype reasoning_tokens: int """ - code: Union[str, "_models.RubricGenerationInputQualityWarningCode"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Stable searchable machine-readable warning code. Required. Known values are: \"empty_prompt\", - \"short_prompt\", \"empty_agent_instructions\", \"short_agent_instructions\", - \"empty_dataset_content\", \"short_dataset_content\", \"low_trace_count\", and - \"insufficient_total_input\".""" - severity: Union[str, "_models.RubricGenerationInputQualityWarningSeverity"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Advisory severity. Initial values: ``warning``. Required. \"warning\"""" - message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Human-readable message suitable for direct SDK/CLI/UI display. Must not include raw prompt, - instruction, dataset, or trace text. Required.""" - source: Union[str, "_models.RubricGenerationInputQualityWarningSource"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Which source category the warning applies to. ``aggregate`` is used only for cross-source - warnings. Required. Known values are: \"prompt\", \"agent\", \"dataset\", and \"aggregate\".""" - source_index: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Zero-based index into ``EvaluatorGenerationJob.sources`` when the warning applies to a specific - source. Omitted for aggregate warnings and for warnings not tied to one source.""" + reasoning_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - code: Union[str, "_models.RubricGenerationInputQualityWarningCode"], - severity: Union[str, "_models.RubricGenerationInputQualityWarningSeverity"], - message: str, - source: Union[str, "_models.RubricGenerationInputQualityWarningSource"], - source_index: Optional[int] = None, + reasoning_tokens: int, ) -> None: ... @overload @@ -22566,23 +22920,40 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SASCredentials(BaseCredentials, discriminator="SAS"): - """Shared Access Signature (SAS) credential definition. +class PendingUploadRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Represents a request for a pending upload. - :ivar type: The credential type. Required. Shared Access Signature (SAS) credential. - :vartype type: str or ~azure.ai.projects.models.SAS - :ivar sas_token: SAS token. - :vartype sas_token: str + :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. 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 """ - type: Literal[CredentialType.SAS] = rest_discriminator(name="type", visibility=["read"]) # type: ignore - """The credential type. Required. Shared Access Signature (SAS) credential.""" - sas_token: Optional[str] = rest_field(name="SAS", visibility=["read"]) - """SAS token.""" + 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.BLOB_REFERENCE] = rest_field( + name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + ) + """The type of pending upload. Required. Deprecated: the service never read this value and + silently ignored it. Use TemporaryBlobReference instead.""" @overload def __init__( self, + *, + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], + pending_upload_id: Optional[str] = None, + connection_name: Optional[str] = None, ) -> None: ... @overload @@ -22594,74 +22965,47 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = CredentialType.SAS # type: ignore -class Schedule(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Schedule model. +class PendingUploadResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Represents the response for a pending upload request. - :ivar schedule_id: Identifier of the schedule. Required. - :vartype schedule_id: str - :ivar display_name: Name of the schedule. - :vartype display_name: str - :ivar description: Description of the schedule. - :vartype description: str - :ivar enabled: Enabled status of the schedule. Required. - :vartype enabled: bool - :ivar provisioning_status: Provisioning status of the schedule. Known values are: "Creating", - "Updating", "Deleting", "Succeeded", and "Failed". - :vartype provisioning_status: str or ~azure.ai.projects.models.ScheduleProvisioningStatus - :ivar trigger: Trigger for the schedule. Required. - :vartype trigger: ~azure.ai.projects.models.Trigger - :ivar task: Task for the schedule. Required. - :vartype task: ~azure.ai.projects.models.ScheduleTask - :ivar tags: Schedule's tags. Unlike properties, tags are fully mutable. - :vartype tags: dict[str, str] - :ivar properties: Schedule's properties. Unlike tags, properties are add-only. Once added, a - property cannot be removed. - :vartype properties: dict[str, str] - :ivar system_data: System metadata for the resource. Required. - :vartype system_data: dict[str, str] + :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. 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 """ - schedule_id: str = rest_field(name="id", visibility=["read"]) - """Identifier of the schedule. Required.""" - display_name: Optional[str] = rest_field( - name="displayName", visibility=["read", "create", "update", "delete", "query"] + blob_reference: "_models.BlobReference" = rest_field( + name="blobReference", visibility=["read", "create", "update", "delete", "query"] ) - """Name of the schedule.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description of the schedule.""" - enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Enabled status of the schedule. Required.""" - provisioning_status: Optional[Union[str, "_models.ScheduleProvisioningStatus"]] = rest_field( - name="provisioningStatus", visibility=["read"] + """Container-level read, write, list SAS. Required.""" + pending_upload_id: str = rest_field( + name="pendingUploadId", visibility=["read", "create", "update", "delete", "query"] ) - """Provisioning status of the schedule. Known values are: \"Creating\", \"Updating\", - \"Deleting\", \"Succeeded\", and \"Failed\".""" - trigger: "_models.Trigger" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Trigger for the schedule. Required.""" - task: "_models.ScheduleTask" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Task for the schedule. Required.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Schedule's tags. Unlike properties, tags are fully mutable.""" - properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Schedule's properties. Unlike tags, properties are add-only. Once added, a property cannot be - removed.""" - system_data: dict[str, str] = rest_field(name="systemData", visibility=["read"]) - """System metadata for the resource. Required.""" + """ID for this upload request. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Version of asset to be created if user did not specify version when initially creating upload.""" + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] = rest_field( + name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + ) + """The type of pending upload. Required. Deprecated: the service never read this value and + silently ignored it. Use TemporaryBlobReference instead.""" @overload def __init__( self, *, - enabled: bool, - trigger: "_models.Trigger", - task: "_models.ScheduleTask", - display_name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, - properties: Optional[dict[str, str]] = None, + blob_reference: "_models.BlobReference", + pending_upload_id: str, + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], + version: Optional[str] = None, ) -> None: ... @overload @@ -22675,34 +23019,29 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ScheduleRoutineTrigger( - RoutineTrigger, discriminator="schedule" +class PerRecipientSchedule( + TelephonyCampaignSchedule, discriminator="recipient" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A recurring cron-based routine trigger. + """Uses each recipient's scheduled_at: RFC 3339 with timezone in Datasets, Unix seconds for inline + recipients. - :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 + :ivar expires_at: Exclusive deadline for new attempts, including retries; active calls may + finish. Must be later than every scheduled_at. + :vartype expires_at: ~datetime.datetime + :ivar type: Identifies scheduling with a separate earliest dispatch time for each recipient. + Required. A separate earliest dispatch time for each recipient. + :vartype type: str or ~azure.ai.projects.models.RECIPIENT """ - 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.""" + type: Literal[TelephonyCampaignScheduleType.RECIPIENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Identifies scheduling with a separate earliest dispatch time for each recipient. Required. A + separate earliest dispatch time for each recipient.""" @overload def __init__( self, *, - cron_expression: str, - time_zone: str, + expires_at: Optional[datetime.datetime] = None, ) -> None: ... @overload @@ -22714,47 +23053,37 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RoutineTriggerType.SCHEDULE # type: ignore + self.type = TelephonyCampaignScheduleType.RECIPIENT # type: ignore -class ScheduleRun(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Schedule run model. +class TelephonyAddress(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Shared source, recipient and transfer address. Connections validate each role before dialing; + unsupported types fail. New types may be added. - :ivar run_id: Identifier of the schedule run. Required. - :vartype run_id: str - :ivar schedule_id: Identifier of the schedule. Required. - :vartype schedule_id: str - :ivar success: Trigger success status of the schedule run. Required. - :vartype success: bool - :ivar trigger_time: Trigger time of the schedule run. - :vartype trigger_time: ~datetime.datetime - :ivar error: Error information for the schedule run. - :vartype error: str - :ivar properties: Properties of the schedule run. Required. - :vartype properties: dict[str, str] + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + PhoneNumber, SipAddress, TeamsAddress + + :ivar type: Endpoint address type. Required. Known values are: "phone_number", "teams", and + "sip". + :vartype type: str or ~azure.ai.projects.models.TelephonyAddressType + :ivar value: Concrete address value. Known variants apply their format constraints; unknown + variants are rejected before dialing. Required. + :vartype value: str """ - run_id: str = rest_field(name="id", visibility=["read"]) - """Identifier of the schedule run. Required.""" - schedule_id: str = rest_field(name="scheduleId", visibility=["read", "create", "update", "delete", "query"]) - """Identifier of the schedule. Required.""" - success: bool = rest_field(visibility=["read"]) - """Trigger success status of the schedule run. Required.""" - trigger_time: Optional[datetime.datetime] = rest_field( - name="triggerTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" - ) - """Trigger time of the schedule run.""" - error: Optional[str] = rest_field(visibility=["read"]) - """Error information for the schedule run.""" - properties: dict[str, str] = rest_field(visibility=["read"]) - """Properties of the schedule run. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Endpoint address type. Required. Known values are: \"phone_number\", \"teams\", and \"sip\".""" + value: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Concrete address value. Known variants apply their format constraints; unknown variants are + rejected before dialing. Required.""" @overload def __init__( self, *, - schedule_id: str, - trigger_time: Optional[datetime.datetime] = None, + type: str, + value: str, ) -> None: ... @overload @@ -22768,26 +23097,25 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SessionConfiguration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Session defaults applied to sessions created for a hosted agent version. +class PhoneNumber( + TelephonyAddress, discriminator="phone_number" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Phone-number address used by supported source and destination roles. - :ivar idle_timeout_seconds: The idle duration, in seconds, before a session's sandbox is - suspended. When omitted, the server defaults to 900 seconds. Must be between 120 and 14400 - seconds (4 hours). - :vartype idle_timeout_seconds: ~datetime.timedelta + :ivar type: The phone-number address type. Required. An E.164 phone number. + :vartype type: str or ~azure.ai.projects.models.PHONE_NUMBER + :ivar value: E.164 phone number. Required. + :vartype value: str """ - idle_timeout_seconds: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" - ) - """The idle duration, in seconds, before a session's sandbox is suspended. When omitted, the - server defaults to 900 seconds. Must be between 120 and 14400 seconds (4 hours).""" + type: Literal[TelephonyAddressType.PHONE_NUMBER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The phone-number address type. Required. An E.164 phone number.""" @overload def __init__( self, *, - idle_timeout_seconds: Optional[datetime.timedelta] = None, + value: str, ) -> None: ... @overload @@ -22799,40 +23127,26 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = TelephonyAddressType.PHONE_NUMBER # type: ignore -class SessionDirectoryEntry(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A single entry in a directory listing. +class PickPropertiesVoiceAgentAudioConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The template for picking properties. - :ivar name: The name of the file or directory. Required. - :vartype name: str - :ivar size: The size in bytes (0 for directories). Required. - :vartype size: int - :ivar is_directory: Whether this entry is a directory. Required. - :vartype is_directory: bool - :ivar modified_time: The Unix timestamp (in seconds) when the file was last modified. Required. - :vartype modified_time: ~datetime.datetime + :ivar output: Output (agent speech) audio configuration. + :vartype output: ~azure.ai.projects.models.VoiceAgentAudioOutputConfig """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the file or directory. Required.""" - size: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The size in bytes (0 for directories). Required.""" - is_directory: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether this entry is a directory. Required.""" - modified_time: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + output: Optional["_models.VoiceAgentAudioOutputConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The Unix timestamp (in seconds) when the file was last modified. Required.""" + """Output (agent speech) audio configuration.""" @overload def __init__( self, *, - name: str, - size: int, - is_directory: bool, - modified_time: datetime.datetime, + output: Optional["_models.VoiceAgentAudioOutputConfig"] = None, ) -> None: ... @overload @@ -22846,27 +23160,36 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SessionFileWriteResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Response from uploading a file to a session sandbox. +class ProceduralMemoryItem( + MemoryItem, discriminator="procedural" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A memory item containing a procedure extracted from conversations. - :ivar path: The path where the file was written, relative to the session home directory. + :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 path: str - :ivar bytes_written: Number of bytes written. Required. - :vartype bytes_written: int + :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 """ - path: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The path where the file was written, relative to the session home directory. Required.""" - bytes_written: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of bytes written. Required.""" + 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, *, - path: str, - bytes_written: int, + memory_id: str, + updated_at: datetime.datetime, + scope: str, + content: str, ) -> None: ... @overload @@ -22878,53 +23201,142 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.kind = MemoryItemKind.PROCEDURAL # type: ignore -class SessionLogEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A single Server-Sent Event frame emitted by the hosted agent session log stream. +class ProgrammaticToolCallingParam(Tool, discriminator="programmatic_tool_calling"): + """ProgrammaticToolCallingParam. - Each frame contains an ``event`` field identifying the event type and a ``data`` - field carrying the payload as plain text. Although the current ``data`` payload - is JSON-formatted, its schema is not contractual — additional keys may appear - and the format may change over time. Clients should treat ``data`` as an - opaque string and optionally attempt JSON parsing. + :ivar type: The type of the tool. Always ``programmatic_tool_calling``. Required. + PROGRAMMATIC_TOOL_CALLING. + :vartype type: str or ~azure.ai.projects.models.PROGRAMMATIC_TOOL_CALLING + """ - New event types may be added in the future. Clients should gracefully - ignore unrecognized event types. + type: Literal[ToolType.PROGRAMMATIC_TOOL_CALLING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``programmatic_tool_calling``. Required. + PROGRAMMATIC_TOOL_CALLING.""" - Wire format: + @overload + def __init__( + self, + ) -> None: ... - .. code-block:: + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ - event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting server on port 18080"} + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = ToolType.PROGRAMMATIC_TOOL_CALLING # type: ignore - event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} - :ivar event: The SSE event type. Currently ``log``, but additional event types may be added in - the future. Clients should ignore unrecognized event types. Required. "log" - :vartype event: str or ~azure.ai.projects.models.SessionLogEventType - :ivar data: The event payload as plain text. Currently JSON-formatted but the schema is not - contractual and may change. Required. - :vartype data: str +class PromptAgentDefinition( + AgentDefinition, discriminator="prompt" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The prompt 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. PROMPT. + :vartype kind: str or ~azure.ai.projects.models.PROMPT + :ivar harness: The managed runtime and agent loop used to execute this prompt agent. + :vartype harness: ~azure.ai.projects.models.AgentHarness + :ivar model: The model deployment to use for this agent. Required. + :vartype model: str + :ivar instructions: A system (or developer) message inserted into the model's context. + :vartype instructions: str + :ivar skills: The Foundry skills available to this prompt agent. An omitted skill version is + resolved and pinned when the agent version is created. + :vartype skills: list[~azure.ai.projects.models.SkillReference] + :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. 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. Defaults to ``1``. + :vartype top_p: float + :ivar reasoning: + :vartype reasoning: ~azure.ai.projects.models.Reasoning + :ivar tools: An array of tools the 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 tool_choice: How the model should select which tool (or tools) to use when generating a + response. See the ``tools`` parameter to see how to specify which tools the model can call. Is + either a str type or a ToolChoiceParam type. + :vartype tool_choice: str or ~azure.ai.projects.models.ToolChoiceParam + :ivar text: Configuration options for a text response from the model. Can be plain text or + structured JSON data. + :vartype text: ~azure.ai.projects.models.PromptAgentDefinitionTextOptions + :ivar structured_inputs: Set of structured inputs that can participate in prompt template + substitution or tool argument bindings. + :vartype structured_inputs: dict[str, ~azure.ai.projects.models.StructuredInputDefinition] """ - event: Union[str, "_models.SessionLogEventType"] = rest_field( + kind: Literal[AgentKind.PROMPT] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. PROMPT.""" + harness: Optional["_models.AgentHarness"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The managed runtime and agent loop used to execute this prompt agent.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model deployment to use for this agent. Required.""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A system (or developer) message inserted into the model's context.""" + skills: Optional[list["_models.SkillReference"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The SSE event type. Currently ``log``, but additional event types may be added in the future. - Clients should ignore unrecognized event types. Required. \"log\"""" - data: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The event payload as plain text. Currently JSON-formatted but the schema is not contractual and - may change. Required.""" + """The Foundry skills available to this prompt agent. An omitted skill version is resolved and + pinned when the agent version is created.""" + 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. 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. 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 + use by setting the ``tool_choice`` parameter.""" + tool_choice: Optional[Union[str, "_models.ToolChoiceParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """How the model should select which tool (or tools) to use when generating a response. See the + ``tools`` parameter to see how to specify which tools the model can call. Is either a str type + or a ToolChoiceParam type.""" + text: Optional["_models.PromptAgentDefinitionTextOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration options for a text response from the model. Can be plain text or structured JSON + data.""" + structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Set of structured inputs that can participate in prompt template substitution or tool argument + bindings.""" @overload def __init__( self, *, - event: Union[str, "_models.SessionLogEventType"], - data: str, + model: str, + rai_config: Optional["_models.RaiConfig"] = None, + harness: Optional["_models.AgentHarness"] = None, + instructions: Optional[str] = None, + skills: Optional[list["_models.SkillReference"]] = None, + temperature: Optional[float] = None, + top_p: Optional[float] = None, + reasoning: Optional["_models.Reasoning"] = None, + tools: Optional[list["_models.Tool"]] = None, + tool_choice: Optional[Union[str, "_models.ToolChoiceParam"]] = None, + text: Optional["_models.PromptAgentDefinitionTextOptions"] = None, + structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = None, ) -> None: ... @overload @@ -22936,27 +23348,26 @@ 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 -class SharepointGroundingToolParameters(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The sharepoint grounding tool parameters. +class PromptAgentDefinitionTextOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration options for a text response from the model. Can be plain text or structured JSON + data. - :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 format: + :vartype format: ~azure.ai.projects.models.TextResponseFormat """ - project_connections: Optional[list["_models.ToolProjectConnection"]] = rest_field( + format: Optional["_models.TextResponseFormat"] = 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, *, - project_connections: Optional[list["_models.ToolProjectConnection"]] = None, + format: Optional["_models.TextResponseFormat"] = None, ) -> None: ... @overload @@ -22970,32 +23381,38 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SharepointPreviewTool( - Tool, discriminator="sharepoint_grounding_preview" +class PromptBasedEvaluatorDefinition( + EvaluatorDefinition, discriminator="prompt" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """The input definition information for a sharepoint tool as used to configure an agent. + """Prompt-based evaluator. - :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 sharepoint_grounding_preview: The sharepoint grounding tool parameters. Required. - :vartype sharepoint_grounding_preview: - ~azure.ai.projects.models.SharepointGroundingToolParameters + :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[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.""" - sharepoint_grounding_preview: "_models.SharepointGroundingToolParameters" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The sharepoint grounding tool parameters. Required.""" + type: Literal[EvaluatorDefinitionType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Prompt-based definition.""" + prompt_text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The prompt text used for evaluation. Required.""" @overload def __init__( self, *, - sharepoint_grounding_preview: "_models.SharepointGroundingToolParameters", + 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 @@ -23007,52 +23424,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.SHAREPOINT_GROUNDING_PREVIEW # type: ignore + self.type = EvaluatorDefinitionType.PROMPT # type: ignore -class ShellToolboxTool( - ToolboxTool, discriminator="shell" +class PromptDataGenerationJobSource( + DataGenerationJobSource, discriminator="prompt" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A shell tool stored in a toolbox. This model is additive to toolbox configuration and does not - modify the OpenAI tool contract or existing toolbox tool definitions. + """Prompt source for data generation jobs — inline text provided by the user. - :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. + :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 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 type: The type of the tool. Always ``shell``. Required. SHELL. - :vartype type: str or ~azure.ai.projects.models.SHELL - :ivar allowed_callers: - :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] - :ivar environment: The environment in which shell commands are executed. Specify an - automatically provisioned container or an existing container. Required. - :vartype environment: ~azure.ai.projects.models.ToolboxShellEnvironment + :ivar type: The source type for this source, which is Prompt. Required. Prompt source — inline + text provided by the user. + :vartype type: str or ~azure.ai.projects.models.PROMPT + :ivar prompt: Inline prompt text (e.g., agent description, policy text, supplementary context). + Required. + :vartype prompt: str """ - type: Literal[ToolboxToolType.SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``shell``. Required. SHELL.""" - allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - environment: "_models.ToolboxShellEnvironment" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The environment in which shell commands are executed. Specify an automatically provisioned - container or an existing container. Required.""" + 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, *, - environment: "_models.ToolboxShellEnvironment", - name: Optional[str] = None, + prompt: str, description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, - allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = None, ) -> None: ... @overload @@ -23064,47 +23467,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolboxToolType.SHELL # type: ignore + self.type = DataGenerationJobSourceType.PROMPT # type: ignore -class SimpleQnADataGenerationJobConfiguration( - DataGenerationJobConfiguration, discriminator="simple_qna" +class PromptEvaluatorGenerationJobSource( + EvaluatorGenerationJobSource, discriminator="prompt" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """The configuration for a data generation job with SimpleQnA type. + """Prompt source for evaluator generation jobs — inline text provided by the user. - :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 max_samples: Maximum number of samples to generate, up to service-defined limits. + :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 max_samples: int - :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] + :vartype prompt: str """ - 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.""" - max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of samples to generate, up to service-defined limits. Required.""" - 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.""" + 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, *, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, - question_types: Optional[list[Union[str, "_models.SimpleQnAFineTuningQuestionType"]]] = None, + prompt: str, + description: Optional[str] = None, ) -> None: ... @overload @@ -23116,42 +23513,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobType.SIMPLE_QNA # type: ignore + self.type = EvaluatorGenerationJobSourceType.PROMPT # type: ignore -class SimulationSeedDataGenerationJobConfiguration( - DataGenerationJobConfiguration, discriminator="simulation_seed" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """The configuration for a task generation data generation job. Use with multiturn evaluation - scenarios and with prompt, file, or agent sources. Generated dataset rows include fields such - as ``id``, ``category``, ``test_case_description``, and ``desired_num_turns``. +class PromptOptimizationConfiguration( + AgentOptimizationConfigurationBase, discriminator="prompt_optimization" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration for a one-shot prompt transformation without comparative evaluation. - :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 SimulationSeed for this model. Required. - Simulation seed for evaluation scenarios. - :vartype type: str or ~azure.ai.projects.models.SIMULATION_SEED - :ivar max_samples: Maximum number of samples to generate, up to service-defined limits. - Required. - :vartype max_samples: int + :ivar type: Optimization type discriminator. Required. One-shot prompt optimization. + :vartype type: str or ~azure.ai.projects.models.PROMPT_OPTIMIZATION + :ivar context: Context used to steer prompt optimization. Omitted when no context is supplied. + :vartype context: list[~azure.ai.projects.models.OptimizationContext] """ - type: Literal[DataGenerationJobType.SIMULATION_SEED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The data generation job type, which is SimulationSeed for this model. Required. Simulation seed - for evaluation scenarios.""" - max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of samples to generate, up to service-defined limits. Required.""" + type: Literal[AgentOptimizationConfigurationType.PROMPT_OPTIMIZATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Optimization type discriminator. Required. One-shot prompt optimization.""" + context: Optional[list["_models.OptimizationContext"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Context used to steer prompt optimization. Omitted when no context is supplied.""" @overload def __init__( self, *, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, + context: Optional[list["_models.OptimizationContext"]] = None, ) -> None: ... @overload @@ -23163,30 +23550,61 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobType.SIMULATION_SEED # type: ignore + self.type = AgentOptimizationConfigurationType.PROMPT_OPTIMIZATION # type: ignore -class SipTelephonyTransferDestination( - TelephonyTransferDestination, discriminator="sip" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A SIP destination for a telephony transfer target. +class ProtocolConfiguration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Per-protocol configuration for the agent endpoint. - :ivar kind: The SIP destination type. Required. A Session Initiation Protocol destination. - :vartype kind: str or ~azure.ai.projects.models.SIP - :ivar value: The SIP or SIPS URI to call. Required. - :vartype value: str + :ivar activity: Configuration for the activity protocol. + :vartype activity: ~azure.ai.projects.models.ActivityProtocolConfiguration + :ivar responses: Configuration for the responses protocol. + :vartype responses: ~azure.ai.projects.models.ResponsesProtocolConfiguration + :ivar a2a: Configuration for the A2A protocol. + :vartype a2a: ~azure.ai.projects.models.A2AProtocolConfiguration + :ivar mcp: Configuration for the MCP protocol. + :vartype mcp: ~azure.ai.projects.models.McpProtocolConfiguration + :ivar invocations: Configuration for the invocations protocol. + :vartype invocations: ~azure.ai.projects.models.InvocationsProtocolConfiguration + :ivar invocations_ws: Configuration for the WebSocket-based invocations protocol. + :vartype invocations_ws: ~azure.ai.projects.models.InvocationsWsProtocolConfiguration """ - kind: Literal[TelephonyTransferDestinationKind.SIP] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The SIP destination type. Required. A Session Initiation Protocol destination.""" - value: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The SIP or SIPS URI to call. Required.""" + activity: Optional["_models.ActivityProtocolConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for the activity protocol.""" + responses: Optional["_models.ResponsesProtocolConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for the responses protocol.""" + a2a: Optional["_models.A2AProtocolConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for the A2A protocol.""" + mcp: Optional["_models.McpProtocolConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for the MCP protocol.""" + invocations: Optional["_models.InvocationsProtocolConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for the invocations protocol.""" + invocations_ws: Optional["_models.InvocationsWsProtocolConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for the WebSocket-based invocations protocol.""" @overload def __init__( self, *, - value: str, + activity: Optional["_models.ActivityProtocolConfiguration"] = None, + responses: Optional["_models.ResponsesProtocolConfiguration"] = None, + a2a: Optional["_models.A2AProtocolConfiguration"] = None, + mcp: Optional["_models.McpProtocolConfiguration"] = None, + invocations: Optional["_models.InvocationsProtocolConfiguration"] = None, + invocations_ws: Optional["_models.InvocationsWsProtocolConfiguration"] = None, ) -> None: ... @overload @@ -23198,52 +23616,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = TelephonyTransferDestinationKind.SIP # type: ignore -class SkillDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A skill resource. +class ProtocolVersionRecord(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A record mapping for a single protocol and its version. - :ivar id: The unique identifier of the skill. Required. - :vartype id: str - :ivar name: The unique name of the skill. Required. - :vartype name: str - :ivar description: A human-readable description of the skill. Required. - :vartype description: str - :ivar created_at: The Unix timestamp (seconds) when the skill was created. Required. - :vartype created_at: ~datetime.datetime - :ivar default_version: The default version for the skill. Can be changed via updateSkill. - Required. - :vartype default_version: str - :ivar latest_version: The latest version for the skill. Required. - :vartype latest_version: str + :ivar protocol: The protocol type. Required. Known values are: "activity", "responses", "a2a", + "mcp", "invocations", "voice", "invocations_ws", and "voice_conversation_engine". + :vartype protocol: str or ~azure.ai.projects.models.AgentEndpointProtocol + :ivar version: The version string for the protocol, e.g. 'v0.1.1'. Required. + :vartype version: str """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique identifier of the skill. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique name of the skill. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A human-readable description of the skill. Required.""" - created_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + protocol: Union[str, "_models.AgentEndpointProtocol"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The Unix timestamp (seconds) when the skill was created. Required.""" - default_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The default version for the skill. Can be changed via updateSkill. Required.""" - latest_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The latest version for the skill. Required.""" + """The protocol type. Required. Known values are: \"activity\", \"responses\", \"a2a\", \"mcp\", + \"invocations\", \"voice\", \"invocations_ws\", and \"voice_conversation_engine\".""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version string for the protocol, e.g. 'v0.1.1'. Required.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - name: str, - description: str, - created_at: datetime.datetime, - default_version: str, - latest_version: str, + protocol: Union[str, "_models.AgentEndpointProtocol"], + version: str, ) -> None: ... @overload @@ -23257,50 +23655,34 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SkillInlineContent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Inline content for defining a simple skill without uploading files. Follows the agentskills.io - SKILL.md specification. +class RaiConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration for Responsible AI (RAI) content filtering and safety features. - :ivar description: A human-readable description of what the skill does and when to use it. - Required. - :vartype description: str - :ivar instructions: The skill instructions in markdown format. This is the body content of the - SKILL.md file. Required. - :vartype instructions: str - :ivar license: License name or reference to a bundled license file. - :vartype license: str - :ivar compatibility: Environment requirements or compatibility notes for the skill. - :vartype compatibility: str - :ivar metadata: Arbitrary key-value metadata for additional properties. - :vartype metadata: dict[str, str] - :ivar allowed_tools: List of pre-approved tools the skill may use. Experimental. - :vartype allowed_tools: list[str] + :ivar rai_policy_name: The name of the RAI policy to apply. Required. + :vartype rai_policy_name: str + :ivar invocations_moderation: Author-declared configuration telling the platform where + user/agent text lives in the agent-defined invocations request/response bodies, so + content-safety guardrails can extract and moderate it. Optional; a rai_config without it leaves + the invocations path without content-safety moderation. + :vartype invocations_moderation: ~azure.ai.projects.models.RaiInvocationModeration """ - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A human-readable description of what the skill does and when to use it. Required.""" - instructions: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The skill instructions in markdown format. This is the body content of the SKILL.md file. - Required.""" - license: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """License name or reference to a bundled license file.""" - compatibility: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Environment requirements or compatibility notes for the skill.""" - metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Arbitrary key-value metadata for additional properties.""" - allowed_tools: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """List of pre-approved tools the skill may use. Experimental.""" + rai_policy_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the RAI policy to apply. Required.""" + invocations_moderation: Optional["_models.RaiInvocationModeration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Author-declared configuration telling the platform where user/agent text lives in the + agent-defined invocations request/response bodies, so content-safety guardrails can extract and + moderate it. Optional; a rai_config without it leaves the invocations path without + content-safety moderation.""" @overload def __init__( self, *, - description: str, - instructions: str, - license: Optional[str] = None, - compatibility: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - allowed_tools: Optional[list[str]] = None, + rai_policy_name: str, + invocations_moderation: Optional["_models.RaiInvocationModeration"] = None, ) -> None: ... @overload @@ -23314,31 +23696,68 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SkillReference(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A reference to a versioned Foundry skill. +class RaiInvocationModeration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Declares where request/response text lives so content-safety guardrails can extract it. - :ivar name: The name of the skill. Required. - :vartype name: str - :ivar version: The skill version. If omitted, the current default version is resolved and - pinned when the agent version is created. - :vartype version: str + :ivar input_content_type: How the REQUEST body is parsed. When omitted, the service defaults to + ``json``. Known values are: "json" and "text". + :vartype input_content_type: str or ~azure.ai.projects.models.RaiInvocationContentType + :ivar output_content_type: How the RESPONSE body is parsed. When omitted, the service defaults + to ``json``. Known values are: "json" and "text". + :vartype output_content_type: str or ~azure.ai.projects.models.RaiInvocationContentType + :ivar response_mode: Author-declared response shape; drives which output gate runs and which + fields are required. Required. Known values are: "non_streaming", "streaming", and "both". + :vartype response_mode: str or ~azure.ai.projects.models.RaiInvocationMode + :ivar input_paths: Path(s) to user text in the REQUEST body. Required when input_content_type + is ``json``. + :vartype input_paths: list[str] + :ivar output_paths: Path(s) to agent text in a NON-STREAMING response body. Required when + response_mode is non_streaming/both and output_content_type is ``json``. + :vartype output_paths: list[str] + :ivar stream_selectors: One SSE event->field selector per event type carrying text. Required + when response_mode is streaming/both and output_content_type is ``json``. + :vartype stream_selectors: list[~azure.ai.projects.models.RaiSseTextSelector] """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the skill. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The skill version. If omitted, the current default version is resolved and pinned when the - agent version is created.""" - - @overload - def __init__( - self, - *, - name: str, - version: Optional[str] = None, - ) -> None: ... - - @overload + input_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """How the REQUEST body is parsed. When omitted, the service defaults to ``json``. Known values + are: \"json\" and \"text\".""" + output_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """How the RESPONSE body is parsed. When omitted, the service defaults to ``json``. Known values + are: \"json\" and \"text\".""" + response_mode: Union[str, "_models.RaiInvocationMode"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Author-declared response shape; drives which output gate runs and which fields are required. + Required. Known values are: \"non_streaming\", \"streaming\", and \"both\".""" + input_paths: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Path(s) to user text in the REQUEST body. Required when input_content_type is ``json``.""" + output_paths: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Path(s) to agent text in a NON-STREAMING response body. Required when response_mode is + non_streaming/both and output_content_type is ``json``.""" + stream_selectors: Optional[list["_models.RaiSseTextSelector"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """One SSE event->field selector per event type carrying text. Required when response_mode is + streaming/both and output_content_type is ``json``.""" + + @overload + def __init__( + self, + *, + response_mode: Union[str, "_models.RaiInvocationMode"], + input_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = None, + output_content_type: Optional[Union[str, "_models.RaiInvocationContentType"]] = None, + input_paths: Optional[list[str]] = None, + output_paths: Optional[list[str]] = None, + stream_selectors: Optional[list["_models.RaiSseTextSelector"]] = None, + ) -> None: ... + + @overload def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. @@ -23349,32 +23768,28 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SkillReferenceParam( - ContainerSkill, discriminator="skill_reference" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """SkillReferenceParam. +class RaiSseTextSelector(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An SSE event-type to text-field selector for streaming invocation output. - :ivar type: References a skill created with the /v1/skills endpoint. Required. SKILL_REFERENCE. - :vartype type: str or ~azure.ai.projects.models.SKILL_REFERENCE - :ivar skill_id: The ID of the referenced skill. Required. - :vartype skill_id: str - :ivar version: Optional skill version. Use a positive integer or 'latest'. Omit for default. - :vartype version: str + :ivar event_type: The SSE event ``type`` value that carries text. Required. + :vartype event_type: str + :ivar text_field: The field on a matched event holding the text delta. When omitted, the + service defaults to ``delta``. + :vartype text_field: str """ - type: Literal[ContainerSkillType.SKILL_REFERENCE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """References a skill created with the /v1/skills endpoint. Required. SKILL_REFERENCE.""" - skill_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the referenced skill. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional skill version. Use a positive integer or 'latest'. Omit for default.""" + event_type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The SSE event ``type`` value that carries text. Required.""" + text_field: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The field on a matched event holding the text delta. When omitted, the service defaults to + ``delta``.""" @overload def __init__( self, *, - skill_id: str, - version: Optional[str] = None, + event_type: str, + text_field: Optional[str] = None, ) -> None: ... @overload @@ -23386,51 +23801,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ContainerSkillType.SKILL_REFERENCE # type: ignore -class SkillVersion(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A specific version of a skill. +class RankingOptions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RankingOptions. - :ivar id: The unique identifier of the skill version. Required. - :vartype id: str - :ivar skill_id: The identifier of the parent skill. Required. - :vartype skill_id: str - :ivar name: The name of the skill version. Required. - :vartype name: str - :ivar version: The version identifier. Skill versions are immutable. Required. - :vartype version: str - :ivar description: A human-readable description of the skill version. Required. - :vartype description: str - :ivar created_at: The Unix timestamp (seconds) when the skill version was created. Required. - :vartype created_at: ~datetime.datetime + :ivar ranker: The ranker to use for the file search. Known values are: "auto" and + "default-2024-11-15". + :vartype ranker: str or ~azure.ai.projects.models.RankerVersionType + :ivar score_threshold: The score threshold for the file search, a number between 0 and 1. + Numbers closer to 1 will attempt to return only the most relevant results, but may return fewer + results. + :vartype score_threshold: float + :ivar hybrid_search: Weights that control how reciprocal rank fusion balances semantic + embedding matches versus sparse keyword matches when hybrid search is enabled. + :vartype hybrid_search: ~azure.ai.projects.models.HybridSearchOptions """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique identifier of the skill version. Required.""" - skill_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The identifier of the parent skill. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the skill version. Required.""" - version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version identifier. Skill versions are immutable. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A human-readable description of the skill version. Required.""" - created_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ranker: Optional[Union[str, "_models.RankerVersionType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The Unix timestamp (seconds) when the skill version was created. Required.""" + """The ranker to use for the file search. Known values are: \"auto\" and \"default-2024-11-15\".""" + score_threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The score threshold for the file search, a number between 0 and 1. Numbers closer to 1 will + attempt to return only the most relevant results, but may return fewer results.""" + hybrid_search: Optional["_models.HybridSearchOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Weights that control how reciprocal rank fusion balances semantic embedding matches versus + sparse keyword matches when hybrid search is enabled.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - skill_id: str, - name: str, - version: str, - description: str, - created_at: datetime.datetime, + ranker: Optional[Union[str, "_models.RankerVersionType"]] = None, + score_threshold: Optional[float] = None, + hybrid_search: Optional["_models.HybridSearchOptions"] = None, ) -> None: ... @overload @@ -23444,30 +23851,19 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolChoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """How the model should select which tool (or tools) to use when generating a response. See the - ``tools`` parameter to see how to specify which tools the model can call. +class RealtimeAudioFormats(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeAudioFormats. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ToolChoiceAllowed, SpecificApplyPatchParam, ToolChoiceCodeInterpreter, ToolChoiceComputer, - ToolChoiceComputerUse, ToolChoiceComputerUsePreview, ToolChoiceCustom, ToolChoiceFileSearch, - ToolChoiceFunction, ToolChoiceImageGeneration, ToolChoiceMCP, - SpecificProgrammaticToolCallingParam, SpecificFunctionShellParam, ToolChoiceWebSearchPreview, - ToolChoiceWebSearchPreview20250311 + RealtimeAudioFormatsAudioPcm, RealtimeAudioFormatsAudioPcma, RealtimeAudioFormatsAudioPcmu - :ivar type: Required. Known values are: "allowed_tools", "function", "mcp", "custom", - "programmatic_tool_calling", "apply_patch", "shell", "file_search", "web_search_preview", - "computer_use_preview", "web_search_preview_2025_03_11", "image_generation", - "code_interpreter", "computer", and "computer_use". - :vartype type: str or ~azure.ai.projects.models.ToolChoiceParamType + :ivar type: Required. Known values are: "audio/pcm", "audio/pcmu", and "audio/pcma". + :vartype type: str or ~azure.ai.projects.models.RealtimeAudioFormatsType """ __mapping__: dict[str, _Model] = {} type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"allowed_tools\", \"function\", \"mcp\", \"custom\", - \"programmatic_tool_calling\", \"apply_patch\", \"shell\", \"file_search\", - \"web_search_preview\", \"computer_use_preview\", \"web_search_preview_2025_03_11\", - \"image_generation\", \"code_interpreter\", \"computer\", and \"computer_use\".""" + """Required. Known values are: \"audio/pcm\", \"audio/pcmu\", and \"audio/pcma\".""" @overload def __init__( @@ -23487,19 +23883,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpecificApplyPatchParam(ToolChoiceParam, discriminator="apply_patch"): - """Specific apply patch tool choice. +class RealtimeAudioFormatsAudioPcm( + RealtimeAudioFormats, discriminator="audio/pcm" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeAudioFormatsAudioPcm. - :ivar type: The tool to call. Always ``apply_patch``. Required. APPLY_PATCH. - :vartype type: str or ~azure.ai.projects.models.APPLY_PATCH + :ivar type: Required. AUDIO_PCM. + :vartype type: str or ~azure.ai.projects.models.AUDIO_PCM + :ivar rate: Default value is 24000. + :vartype rate: int """ - type: Literal[ToolChoiceParamType.APPLY_PATCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The tool to call. Always ``apply_patch``. Required. APPLY_PATCH.""" + type: Literal[RealtimeAudioFormatsType.AUDIO_PCM] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. AUDIO_PCM.""" + rate: Optional[Literal[24000]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Default value is 24000.""" @overload def __init__( self, + *, + rate: Optional[Literal[24000]] = None, ) -> None: ... @overload @@ -23511,18 +23915,18 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.APPLY_PATCH # type: ignore + self.type = RealtimeAudioFormatsType.AUDIO_PCM # type: ignore -class SpecificFunctionShellParam(ToolChoiceParam, discriminator="shell"): - """Specific shell tool choice. +class RealtimeAudioFormatsAudioPcma(RealtimeAudioFormats, discriminator="audio/pcma"): + """RealtimeAudioFormatsAudioPcma. - :ivar type: The tool to call. Always ``shell``. Required. SHELL. - :vartype type: str or ~azure.ai.projects.models.SHELL + :ivar type: Required. AUDIO_PCMA. + :vartype type: str or ~azure.ai.projects.models.AUDIO_PCMA """ - type: Literal[ToolChoiceParamType.SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The tool to call. Always ``shell``. Required. SHELL.""" + type: Literal[RealtimeAudioFormatsType.AUDIO_PCMA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. AUDIO_PCMA.""" @overload def __init__( @@ -23538,19 +23942,18 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.SHELL # type: ignore + self.type = RealtimeAudioFormatsType.AUDIO_PCMA # type: ignore -class SpecificProgrammaticToolCallingParam(ToolChoiceParam, discriminator="programmatic_tool_calling"): - """SpecificProgrammaticToolCallingParam. +class RealtimeAudioFormatsAudioPcmu(RealtimeAudioFormats, discriminator="audio/pcmu"): + """RealtimeAudioFormatsAudioPcmu. - :ivar type: The tool to call. Always ``programmatic_tool_calling``. Required. - PROGRAMMATIC_TOOL_CALLING. - :vartype type: str or ~azure.ai.projects.models.PROGRAMMATIC_TOOL_CALLING + :ivar type: Required. AUDIO_PCMU. + :vartype type: str or ~azure.ai.projects.models.AUDIO_PCMU """ - type: Literal[ToolChoiceParamType.PROGRAMMATIC_TOOL_CALLING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The tool to call. Always ``programmatic_tool_calling``. Required. PROGRAMMATIC_TOOL_CALLING.""" + type: Literal[RealtimeAudioFormatsType.AUDIO_PCMU] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. AUDIO_PCMU.""" @overload def __init__( @@ -23566,32 +23969,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.PROGRAMMATIC_TOOL_CALLING # type: ignore + self.type = RealtimeAudioFormatsType.AUDIO_PCMU # type: ignore -class SteeringPromptOptimizationContext( - OptimizationContext, discriminator="steering_prompt" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Natural-language guidance for the desired optimization. +class RealtimeClientEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A realtime client event. - :ivar type: Optimization context type discriminator. Required. Natural-language guidance that - steers the desired optimization. - :vartype type: str or ~azure.ai.projects.models.STEERING_PROMPT - :ivar prompt: Developer guidance describing the desired changes. Required. - :vartype prompt: str + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + RealtimeClientEventConversationItemCreate, RealtimeClientEventConversationItemDelete, + RealtimeClientEventConversationItemRetrieve, RealtimeClientEventConversationItemTruncate, + RealtimeClientEventInputAudioBufferAppend, RealtimeClientEventInputAudioBufferClear, + RealtimeClientEventInputAudioBufferCommit, RealtimeClientEventOutputAudioBufferClear, + RealtimeClientEventResponseCancel, RealtimeClientEventResponseCreate, + VoiceAgentClientEventRtcCallSdpCreate, VoiceAgentClientEventSessionAvatarConnect + + :ivar type: Required. Known values are: "session.avatar.connect", "rtc.call.sdp.create", + "conversation.item.create", "conversation.item.delete", "conversation.item.retrieve", + "conversation.item.truncate", "input_audio_buffer.append", "input_audio_buffer.clear", + "output_audio_buffer.clear", "input_audio_buffer.commit", "response.cancel", "response.create", + and "session.update". + :vartype type: str or ~azure.ai.projects.models.RealtimeClientEventType """ - type: Literal[OptimizationContextType.STEERING_PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Optimization context type discriminator. Required. Natural-language guidance that steers the - desired optimization.""" - prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Developer guidance describing the desired changes. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"session.avatar.connect\", \"rtc.call.sdp.create\", + \"conversation.item.create\", \"conversation.item.delete\", \"conversation.item.retrieve\", + \"conversation.item.truncate\", \"input_audio_buffer.append\", \"input_audio_buffer.clear\", + \"output_audio_buffer.clear\", \"input_audio_buffer.commit\", \"response.cancel\", + \"response.create\", and \"session.update\".""" @overload def __init__( self, *, - prompt: str, + type: str, ) -> None: ... @overload @@ -23603,42 +24015,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = OptimizationContextType.STEERING_PROMPT # type: ignore -class StructuredInputDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """An structured input that can participate in prompt template substitutions and tool argument - binding. +class RealtimeClientEventConversationItemCreate( + RealtimeClientEvent, discriminator="conversation.item.create" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Add a new Item to the Conversation's context, including messages, function calls, and function + call responses. This event can be used both to populate a "history" of the conversation and to + add new items mid-stream, but has the current limitation that it cannot populate assistant + audio messages. If successful, the server will emit a ``conversation.item.added`` event and, + when the item is finalized, a ``conversation.item.done`` event. Otherwise, an ``error`` event + will be sent. - :ivar description: A human-readable description of the input. - :vartype description: str - :ivar default_value: The default value for the input if no run-time value is provided. - :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. The service - defaults to ``false`` if a value is not specified by the caller. - :vartype required: bool + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.create``. Required. + CONVERSATION_ITEM_CREATE. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_CREATE + :ivar previous_item_id: The ID of the preceding item after which the new item will be inserted. + If not set, the new item will be appended to the end of the conversation. If set to ``root``, + the new item will be added to the beginning of the conversation. If set to an existing ID, it + allows an item to be inserted mid-conversation. If the ID cannot be found, an error will be + returned and the item will not be added. + :vartype previous_item_id: str + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem """ - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A human-readable description of the input.""" - default_value: Optional[Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The default value for the input if no run-time value is provided.""" - 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. The service defaults to - ``false`` if a value is not specified by the caller.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.create``. Required. CONVERSATION_ITEM_CREATE.""" + previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the preceding item after which the new item will be inserted. If not set, the new + item will be appended to the end of the conversation. If set to ``root``, the new item will be + added to the beginning of the conversation. If set to an existing ID, it allows an item to be + inserted mid-conversation. If the ID cannot be found, an error will be returned and the item + will not be added.""" + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - description: Optional[str] = None, - default_value: Optional[Any] = None, - schema: Optional[dict[str, Any]] = None, - required: Optional[bool] = None, + item: "_models.RealtimeConversationItem", + event_id: Optional[str] = None, + previous_item_id: Optional[str] = None, ) -> None: ... @overload @@ -23650,40 +24073,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.CONVERSATION_ITEM_CREATE # type: ignore -class StructuredOutputDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A structured output that can be produced by the agent. +class RealtimeClientEventConversationItemDelete( + RealtimeClientEvent, discriminator="conversation.item.delete" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Send this event when you want to remove any item from the conversation history. The server will + respond with a ``conversation.item.deleted`` event, unless the item does not exist in the + conversation history, in which case the server will respond with an error. - :ivar name: The name of the structured output. Required. - :vartype name: str - :ivar description: A description of the output to emit. Used by the model to determine when to - emit the output. Required. - :vartype description: str - :ivar schema: The JSON schema for the structured output. Required. - :vartype schema: dict[str, any] - :ivar strict: Whether to enforce strict validation. Default ``true``. Required. - :vartype strict: bool + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.delete``. Required. + CONVERSATION_ITEM_DELETE. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_DELETE + :ivar item_id: The ID of the item to delete. Required. + :vartype item_id: str """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the structured output. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A description of the output to emit. Used by the model to determine when to emit the output. - Required.""" - schema: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The JSON schema for the structured output. Required.""" - strict: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether to enforce strict validation. Default ``true``. Required.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_DELETE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.delete``. Required. CONVERSATION_ITEM_DELETE.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item to delete. Required.""" @overload def __init__( self, *, - name: str, - description: str, - schema: dict[str, Any], - strict: bool, + item_id: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -23695,60 +24116,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.CONVERSATION_ITEM_DELETE # type: ignore -class SupervisedFineTuningDataGenerationJob( - DataGenerationJob, discriminator="supervised_finetuning_preview" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Supervised fine-tuning data generation job resource. This is a preview feature. +class RealtimeClientEventConversationItemRetrieve( + RealtimeClientEvent, discriminator="conversation.item.retrieve" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Send this event when you want to retrieve the server's representation of a specific item in the + conversation history. This is useful, for example, to inspect user audio after noise + cancellation and VAD. The server will respond with a ``conversation.item.retrieved`` event, + unless the item does not exist in the conversation history, in which case the server will + respond with an error. - :ivar id: Server-assigned unique identifier. Required. - :vartype id: str - :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 name: The display name of the data generation job. Required. - :vartype name: str - :ivar sources: The sources used for the data generation job. Required. - :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] - :ivar generation_configuration: The generation configuration for the data generation job. - Required. - :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration - :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds - since January 1, 1970). Required. - :vartype created_at: ~datetime.datetime - :ivar finished_at: The timestamp when the job was finished, represented in Unix time (seconds - since January 1, 1970). - :vartype finished_at: ~datetime.datetime - :ivar scenario: The scenario of the data generation job, which is Supervised Fine-tuning - preview for this model. Required. Supervised Fine-tuning preview scenario. - :vartype scenario: str or ~azure.ai.projects.models.SUPERVISED_FINETUNING_PREVIEW - :ivar output_configuration: Optional file output configuration for the generated supervised - fine-tuning data. - :vartype output_configuration: - ~azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.retrieve``. Required. + CONVERSATION_ITEM_RETRIEVE. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_RETRIEVE + :ivar item_id: The ID of the item to retrieve. Required. + :vartype item_id: str """ - scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The scenario of the data generation job, which is Supervised Fine-tuning preview for this - model. Required. Supervised Fine-tuning preview scenario.""" - output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional file output configuration for the generated supervised fine-tuning data.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_RETRIEVE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.retrieve``. Required. CONVERSATION_ITEM_RETRIEVE.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item to retrieve. Required.""" @overload def __init__( self, *, - name: str, - sources: list["_models.DataGenerationJobSource"], - generation_configuration: "_models.DataGenerationJobConfiguration", - output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = None, + item_id: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -23760,47 +24161,57 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.scenario = DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW # type: ignore + self.type = RealtimeClientEventType.CONVERSATION_ITEM_RETRIEVE # type: ignore -class SupervisedFineTuningDataGenerationJobInputs( - DataGenerationJobInputs, discriminator="supervised_finetuning_preview" +class RealtimeClientEventConversationItemTruncate( + RealtimeClientEvent, discriminator="conversation.item.truncate" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Caller-supplied inputs for a supervised fine-tuning data generation job. This is a preview - feature. + """Send this event to truncate a previous assistant message’s audio. The server will produce audio + faster than realtime, so this event is useful when the user interrupts to truncate audio that + has already been sent to the client but not yet played. This will synchronize the server's + understanding of the audio with the client's playback. Truncating audio will delete the + server-side text transcript to ensure there is not text in the context that hasn't been heard + by the user. If successful, the server will respond with a ``conversation.item.truncated`` + event. - :ivar name: The display name of the data generation job. Required. - :vartype name: str - :ivar sources: The sources used for the data generation job. Required. - :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] - :ivar generation_configuration: The generation configuration for the data generation job. + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.truncate``. Required. + CONVERSATION_ITEM_TRUNCATE. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_TRUNCATE + :ivar item_id: The ID of the assistant message item to truncate. Only assistant message items + can be truncated. Required. + :vartype item_id: str + :ivar content_index: The index of the content part to truncate. Set this to ``0``. Required. + :vartype content_index: int + :ivar audio_end_ms: Inclusive duration up to which audio is truncated, in milliseconds. If the + audio_end_ms is greater than the actual audio duration, the server will respond with an error. Required. - :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration - :ivar scenario: The scenario of the data generation job, which is Supervised Fine-tuning - preview for this model. Required. Supervised Fine-tuning preview scenario. - :vartype scenario: str or ~azure.ai.projects.models.SUPERVISED_FINETUNING_PREVIEW - :ivar output_configuration: Optional file output configuration for the generated supervised - fine-tuning data. - :vartype output_configuration: - ~azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration + :vartype audio_end_ms: int """ - scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The scenario of the data generation job, which is Supervised Fine-tuning preview for this - model. Required. Supervised Fine-tuning preview scenario.""" - output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional file output configuration for the generated supervised fine-tuning data.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.CONVERSATION_ITEM_TRUNCATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.truncate``. Required. CONVERSATION_ITEM_TRUNCATE.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the assistant message item to truncate. Only assistant message items can be + truncated. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part to truncate. Set this to ``0``. Required.""" + audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Inclusive duration up to which audio is truncated, in milliseconds. If the audio_end_ms is + greater than the actual audio duration, the server will respond with an error. Required.""" @overload def __init__( self, *, - name: str, - sources: list["_models.DataGenerationJobSource"], - generation_configuration: "_models.DataGenerationJobConfiguration", - output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = None, + item_id: str, + content_index: int, + audio_end_ms: int, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -23812,42 +24223,47 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.scenario = DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW # type: ignore + self.type = RealtimeClientEventType.CONVERSATION_ITEM_TRUNCATE # type: ignore -class SupervisedFineTuningDataGenerationJobOutputConfiguration( - _Model +class RealtimeClientEventInputAudioBufferAppend( + RealtimeClientEvent, discriminator="input_audio_buffer.append" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """File output configuration for a supervised fine-tuning data generation job. This is a preview - feature. + """Send this event to append audio bytes to the input audio buffer. The audio buffer is temporary + storage you can write to and later commit. A "commit" will create a new user message item in + the conversation history from the buffer content and clear the buffer. Input audio + transcription (if enabled) will be generated when the buffer is committed. If VAD is enabled + the audio buffer is used to detect speech and the server will decide when to commit. When + Server VAD is disabled, you must commit the audio buffer manually. Input audio noise reduction + operates on writes to the audio buffer. The client may choose how much audio to place in each + event up to a maximum of 15 MiB, for example streaming smaller chunks from the client may allow + the VAD to be more responsive. Unlike most other client events, the server will not send a + confirmation response to this event. - :ivar name: Filename to assign to the generated fine-tuning file. Required. - :vartype name: str - :ivar write_mode: Controls how file outputs are written. If omitted, defaults to ``overwrite`` - and writes only the newly generated fine-tuning file content. Known values are: "overwrite" and - "merge". - :vartype write_mode: str or ~azure.ai.projects.models.DataGenerationJobOutputWriteMode - :ivar merge_file_id: File ID to merge into when ``write_mode`` is ``merge``. - :vartype merge_file_id: str + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.append``. Required. + INPUT_AUDIO_BUFFER_APPEND. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_APPEND + :ivar audio: Base64-encoded audio bytes. This must be in the format specified by the + ``input_audio_format`` field in the session configuration. Required. + :vartype audio: str """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Filename to assign to the generated fine-tuning file. Required.""" - write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Controls how file outputs are written. If omitted, defaults to ``overwrite`` and writes only - the newly generated fine-tuning file content. Known values are: \"overwrite\" and \"merge\".""" - merge_file_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """File ID to merge into when ``write_mode`` is ``merge``.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_APPEND] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.append``. Required. INPUT_AUDIO_BUFFER_APPEND.""" + audio: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64-encoded audio bytes. This must be in the format specified by the ``input_audio_format`` + field in the session configuration. Required.""" @overload def __init__( self, *, - name: str, - write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = None, - merge_file_id: Optional[str] = None, + audio: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -23859,58 +24275,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.INPUT_AUDIO_BUFFER_APPEND # type: ignore -class TaxonomyCategory(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Taxonomy category definition. +class RealtimeClientEventInputAudioBufferClear( + RealtimeClientEvent, discriminator="input_audio_buffer.clear" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Send this event to clear the audio bytes in the buffer. The server will respond with an + ``input_audio_buffer.cleared`` event. - :ivar id: Unique identifier of the taxonomy category. Required. - :vartype id: str - :ivar name: Name of the taxonomy category. Required. - :vartype name: str - :ivar description: Description of the taxonomy category. - :vartype description: str - :ivar risk_category: Risk category associated with this taxonomy category. Required. Known - values are: "HateUnfairness", "Violence", "Sexual", "SelfHarm", "ProtectedMaterial", - "CodeVulnerability", "UngroundedAttributes", "ProhibitedActions", "SensitiveDataLeakage", and - "TaskAdherence". - :vartype risk_category: str or ~azure.ai.projects.models.RiskCategory - :ivar sub_categories: List of taxonomy sub categories. Required. - :vartype sub_categories: list[~azure.ai.projects.models.TaxonomySubCategory] - :ivar properties: Additional properties for the taxonomy category. - :vartype properties: dict[str, str] + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.clear``. Required. + INPUT_AUDIO_BUFFER_CLEAR. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_CLEAR """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Unique identifier of the taxonomy category. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Name of the taxonomy category. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description of the taxonomy category.""" - risk_category: Union[str, "_models.RiskCategory"] = rest_field( - name="riskCategory", visibility=["read", "create", "update", "delete", "query"] - ) - """Risk category associated with this taxonomy category. Required. Known values are: - \"HateUnfairness\", \"Violence\", \"Sexual\", \"SelfHarm\", \"ProtectedMaterial\", - \"CodeVulnerability\", \"UngroundedAttributes\", \"ProhibitedActions\", - \"SensitiveDataLeakage\", and \"TaskAdherence\".""" - sub_categories: list["_models.TaxonomySubCategory"] = rest_field( - name="subCategories", visibility=["read", "create", "update", "delete", "query"] - ) - """List of taxonomy sub categories. Required.""" - properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Additional properties for the taxonomy category.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_CLEAR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.clear``. Required. INPUT_AUDIO_BUFFER_CLEAR.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - name: str, - risk_category: Union[str, "_models.RiskCategory"], - sub_categories: list["_models.TaxonomySubCategory"], - description: Optional[str] = None, - properties: Optional[dict[str, str]] = None, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -23922,43 +24312,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.INPUT_AUDIO_BUFFER_CLEAR # type: ignore -class TaxonomySubCategory(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Taxonomy sub-category definition. +class RealtimeClientEventInputAudioBufferCommit( + RealtimeClientEvent, discriminator="input_audio_buffer.commit" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Send this event to commit the user input audio buffer, which will create a new user message + item in the conversation. This event will produce an error if the input audio buffer is empty. + When in Server VAD mode, the client does not need to send this event, the server will commit + the audio buffer automatically. Committing the input audio buffer will trigger input audio + transcription (if enabled in session configuration), but it will not create a response from + the model. The server will respond with an ``input_audio_buffer.committed`` event. - :ivar id: Unique identifier of the taxonomy sub-category. Required. - :vartype id: str - :ivar name: Name of the taxonomy sub-category. Required. - :vartype name: str - :ivar description: Description of the taxonomy sub-category. - :vartype description: str - :ivar enabled: List of taxonomy items under this sub-category. Required. - :vartype enabled: bool - :ivar properties: Additional properties for the taxonomy sub-category. - :vartype properties: dict[str, str] + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.commit``. Required. + INPUT_AUDIO_BUFFER_COMMIT. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_COMMIT """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Unique identifier of the taxonomy sub-category. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Name of the taxonomy sub-category. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description of the taxonomy sub-category.""" - enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """List of taxonomy items under this sub-category. Required.""" - properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Additional properties for the taxonomy sub-category.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.INPUT_AUDIO_BUFFER_COMMIT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.commit``. Required. INPUT_AUDIO_BUFFER_COMMIT.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - name: str, - enabled: bool, - description: Optional[str] = None, - properties: Optional[dict[str, str]] = None, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -23970,57 +24353,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.INPUT_AUDIO_BUFFER_COMMIT # type: ignore -class TelephonyBinding(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A telephony binding owned by a voice agent. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - TeamsPhoneExtensibilityTelephonyBinding, TwilioTelephonyBinding +class RealtimeClientEventOutputAudioBufferClear( + RealtimeClientEvent, discriminator="output_audio_buffer.clear" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """**WebRTC/SIP Only:** Emit to cut off the current audio response. This will trigger the server + to stop generating audio and emit a ``output_audio_buffer.cleared`` event. This event should be + preceded by a ``response.cancel`` client event to stop the generation of the current response. + `Learn more + `_. - :ivar id: The service-generated binding identifier. Required. - :vartype id: str - :ivar provider: The telephony provider. Required. Known values are: "teams_phone_extensibility" - and "twilio". - :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: The optional display label for the binding. - :vartype label: str - :ivar status: The lifecycle status. Required. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar incoming_call_url: The service-generated webhook URL to configure with the telephony - provider. Required. - :vartype incoming_call_url: str + :ivar event_id: The unique ID of the client event used for error handling. + :vartype event_id: str + :ivar type: The event type, must be ``output_audio_buffer.clear``. Required. + OUTPUT_AUDIO_BUFFER_CLEAR. + :vartype type: str or ~azure.ai.projects.models.OUTPUT_AUDIO_BUFFER_CLEAR """ - __mapping__: dict[str, _Model] = {} - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated binding identifier. Required.""" - provider: str = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) - """The telephony provider. Required. Known values are: \"teams_phone_extensibility\" and - \"twilio\".""" - connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Foundry connection name for the telephony provider. Required.""" - label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The optional display label for the binding.""" - status: Union[str, "_models.TelephonyBindingStatus"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The lifecycle status. Required. Known values are: \"active\" and \"suspended\".""" - incoming_call_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated webhook URL to configure with the telephony provider. Required.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the client event used for error handling.""" + type: Literal[RealtimeClientEventType.OUTPUT_AUDIO_BUFFER_CLEAR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``output_audio_buffer.clear``. Required. OUTPUT_AUDIO_BUFFER_CLEAR.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - provider: str, - connection_name: str, - status: Union[str, "_models.TelephonyBindingStatus"], - incoming_call_url: str, - label: Optional[str] = None, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -24032,53 +24393,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.OUTPUT_AUDIO_BUFFER_CLEAR # type: ignore -class TeamsPhoneExtensibilityTelephonyBinding( - TelephonyBinding, discriminator="teams_phone_extensibility" +class RealtimeClientEventResponseCancel( + RealtimeClientEvent, discriminator="response.cancel" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A Microsoft Teams Phone extensibility binding owned by a voice agent. + """Send this event to cancel an in-progress response. The server will respond with a + ``response.done`` event with a status of ``response.status=cancelled``. If there is no response + to cancel, the server will respond with an error. It's safe to call ``response.cancel`` even if + no response is in progress, an error will be returned the session will remain unaffected. - :ivar id: The service-generated binding identifier. Required. - :vartype id: str - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: The optional display label for the binding. - :vartype label: str - :ivar status: The lifecycle status. Required. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar incoming_call_url: The service-generated webhook URL to configure with the telephony - provider. Required. - :vartype incoming_call_url: str - :ivar provider: The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams - Phone extensibility. - :vartype provider: str or ~azure.ai.projects.models.TEAMS_PHONE_EXTENSIBILITY - :ivar phone_number: The optional display phone number for the Teams resource account. - :vartype phone_number: str - :ivar resource_account_object_id: The Microsoft Teams resource-account object identifier as a - GUID. Required. - :vartype resource_account_object_id: str + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``response.cancel``. Required. RESPONSE_CANCEL. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_CANCEL + :ivar response_id: A specific response ID to cancel - if not provided, will cancel an + in-progress response in the default conversation. + :vartype response_id: str """ - provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams Phone - extensibility.""" - phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The optional display phone number for the Teams resource account.""" - resource_account_object_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Microsoft Teams resource-account object identifier as a GUID. Required.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.RESPONSE_CANCEL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.cancel``. Required. RESPONSE_CANCEL.""" + response_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A specific response ID to cancel - if not provided, will cancel an in-progress response in the + default conversation.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - connection_name: str, - status: Union[str, "_models.TelephonyBindingStatus"], - incoming_call_url: str, - resource_account_object_id: str, - label: Optional[str] = None, - phone_number: Optional[str] = None, + event_id: Optional[str] = None, + response_id: Optional[str] = None, ) -> None: ... @overload @@ -24090,64 +24438,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.provider = TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY # type: ignore - + self.type = RealtimeClientEventType.RESPONSE_CANCEL # type: ignore -class TelephonyBindingListItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A telephony binding returned in a list, including its entity tag. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - TeamsPhoneExtensibilityTelephonyBindingListItem, TwilioTelephonyBindingListItem +class RealtimeClientEventResponseCreate( + RealtimeClientEvent, discriminator="response.create" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """This event instructs the server to create a Response, which means triggering model inference. + When in Server VAD mode, the server will create Responses automatically. A Response will + include at least one Item, and may have two, in which case the second will be a function call. + These Items will be appended to the conversation history by default. The server will respond + with a ``response.created`` event, events for Items and content created, and finally a + ``response.done`` event to indicate the Response is complete. The ``response.create`` event + includes inference configuration like ``instructions`` and ``tools``. If these are set, they + will override the Session's configuration for this Response only. Responses can be created + out-of-band of the default Conversation, meaning that they can have arbitrary input, and it's + possible to disable writing the output to the Conversation. Only one Response can write to the + default Conversation at a time, but otherwise multiple Responses can be created in parallel. + The ``metadata`` field is a good way to disambiguate multiple simultaneous Responses. Clients + can set ``conversation`` to ``none`` to create a Response that does not write to the default + Conversation. Arbitrary input can be provided with the ``input`` field, which is an array + accepting raw Items and references to existing Items. - :ivar id: The service-generated binding identifier. Required. - :vartype id: str - :ivar provider: The telephony provider. Required. Known values are: "teams_phone_extensibility" - and "twilio". - :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: The optional display label for the binding. - :vartype label: str - :ivar status: The lifecycle status. Required. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar incoming_call_url: The service-generated webhook URL to configure with the telephony - provider. Required. - :vartype incoming_call_url: str - :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this - binding. Required. - :vartype etag: str + :ivar event_id: Optional client-generated ID used to identify this event. + :vartype event_id: str + :ivar type: The event type, must be ``response.create``. Required. RESPONSE_CREATE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_CREATE + :ivar response: + :vartype response: ~azure.ai.projects.models.VoiceAgentResponseCreateParams """ - __mapping__: dict[str, _Model] = {} - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated binding identifier. Required.""" - provider: str = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) - """The telephony provider. Required. Known values are: \"teams_phone_extensibility\" and - \"twilio\".""" - connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Foundry connection name for the telephony provider. Required.""" - label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The optional display label for the binding.""" - status: Union[str, "_models.TelephonyBindingStatus"] = rest_field( + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event.""" + type: Literal[RealtimeClientEventType.RESPONSE_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.create``. Required. RESPONSE_CREATE.""" + response: Optional["_models.VoiceAgentResponseCreateParams"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The lifecycle status. Required. Known values are: \"active\" and \"suspended\".""" - incoming_call_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated webhook URL to configure with the telephony provider. Required.""" - etag: str = rest_field(visibility=["read"]) - """The entity tag to send in the ``If-Match`` header when updating or deleting this binding. - Required.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - provider: str, - connection_name: str, - status: Union[str, "_models.TelephonyBindingStatus"], - incoming_call_url: str, - label: Optional[str] = None, + event_id: Optional[str] = None, + response: Optional["_models.VoiceAgentResponseCreateParams"] = None, ) -> None: ... @overload @@ -24159,56 +24493,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeClientEventType.RESPONSE_CREATE # type: ignore -class TeamsPhoneExtensibilityTelephonyBindingListItem( - TelephonyBindingListItem, discriminator="teams_phone_extensibility" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """A Microsoft Teams Phone extensibility binding returned in a list, including its entity tag. +class RealtimeConversationItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A single item within a Realtime conversation. - :ivar id: The service-generated binding identifier. Required. - :vartype id: str - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: The optional display label for the binding. - :vartype label: str - :ivar status: The lifecycle status. Required. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar incoming_call_url: The service-generated webhook URL to configure with the telephony - provider. Required. - :vartype incoming_call_url: str - :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this - binding. Required. - :vartype etag: str - :ivar provider: The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams - Phone extensibility. - :vartype provider: str or ~azure.ai.projects.models.TEAMS_PHONE_EXTENSIBILITY - :ivar phone_number: The optional display phone number for the Teams resource account. - :vartype phone_number: str - :ivar resource_account_object_id: The Microsoft Teams resource-account object identifier as a - GUID. Required. - :vartype resource_account_object_id: str + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + RealtimeConversationItemFunctionCall, RealtimeConversationItemFunctionCallOutput, + RealtimeMCPApprovalRequest, RealtimeMCPApprovalResponse, RealtimeMCPToolCall, + RealtimeMCPListTools, RealtimeConversationItemMessage, VoiceAgentSystemToolItem + + :ivar type: Required. Known values are: "system_tool", "function_call", "function_call_output", + "mcp_approval_response", "mcp_list_tools", "mcp_call", "mcp_approval_request", and "message". + :vartype type: str or ~azure.ai.projects.models.RealtimeConversationItemType """ - provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams Phone - extensibility.""" - phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The optional display phone number for the Teams resource account.""" - resource_account_object_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Microsoft Teams resource-account object identifier as a GUID. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"system_tool\", \"function_call\", \"function_call_output\", + \"mcp_approval_response\", \"mcp_list_tools\", \"mcp_call\", \"mcp_approval_request\", and + \"message\".""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - connection_name: str, - status: Union[str, "_models.TelephonyBindingStatus"], - incoming_call_url: str, - resource_account_object_id: str, - label: Optional[str] = None, - phone_number: Optional[str] = None, + type: str, ) -> None: ... @overload @@ -24220,32 +24531,71 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.provider = TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY # type: ignore -class TeamsTelephonyTransferDestination( - TelephonyTransferDestination, discriminator="teams" +class RealtimeConversationItemFunctionCall( + RealtimeConversationItem, discriminator="function_call" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A Microsoft Teams destination for a telephony transfer target. + """Realtime function call item. - :ivar kind: The Microsoft Teams destination type. Required. A Microsoft Teams user or - resource-account destination. - :vartype kind: str or ~azure.ai.projects.models.TEAMS - :ivar value: The Microsoft Teams user or resource-account identifier. Required. - :vartype value: str + :ivar id: The unique ID of the item. This may be provided by the client or generated by the + server. + :vartype id: str + :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional + when creating a new item. Default value is "realtime.item". + :vartype object: str + :ivar type: The type of the item. Always ``function_call``. Required. FUNCTION_CALL. + :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL + :ivar status: The status of the item. Has no effect on the conversation. Is one of the + following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] + :vartype status: str or str or str + :ivar call_id: The ID of the function call. + :vartype call_id: str + :ivar name: The name of the function being called. Required. + :vartype name: str + :ivar arguments: The arguments of the function call. This is a JSON-encoded string representing + the arguments passed to the function, for example ``{"arg1": "value1", "arg2": 42}``. Required. + :vartype arguments: str + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str """ - kind: Literal[TelephonyTransferDestinationKind.TEAMS] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Microsoft Teams destination type. Required. A Microsoft Teams user or resource-account - destination.""" - value: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Microsoft Teams user or resource-account identifier. Required.""" + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the item. This may be provided by the client or generated by the server.""" + object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the API object being returned - always ``realtime.item``. Optional when creating + a new item. Default value is \"realtime.item\".""" + type: Literal[RealtimeConversationItemType.FUNCTION_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the item. Always ``function_call``. Required. FUNCTION_CALL.""" + status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The status of the item. Has no effect on the conversation. Is one of the following types: + Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" + call_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the function call.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function being called. Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The arguments of the function call. This is a JSON-encoded string representing the arguments + passed to the function, for example ``{\"arg1\": \"value1\", \"arg2\": 42}``. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" @overload def __init__( self, *, - value: str, + name: str, + arguments: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + object: Optional[Literal["realtime.item"]] = None, + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, + call_id: Optional[str] = None, ) -> None: ... @overload @@ -24257,26 +24607,75 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = TelephonyTransferDestinationKind.TEAMS # type: ignore + self.type = RealtimeConversationItemType.FUNCTION_CALL # type: ignore -class TelemetryConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Customer-supplied telemetry configuration for exporting container logs, traces, and metrics. +class RealtimeConversationItemFunctionCallOutput( + RealtimeConversationItem, discriminator="function_call_output" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Realtime function call output item. - :ivar endpoints: Customer-supplied telemetry export endpoint configurations. Required. - :vartype endpoints: list[~azure.ai.projects.models.TelemetryEndpoint] + :ivar id: The unique ID of the item. This may be provided by the client or generated by the + server. + :vartype id: str + :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional + when creating a new item. Default value is "realtime.item". + :vartype object: str + :ivar type: The type of the item. Always ``function_call_output``. Required. + FUNCTION_CALL_OUTPUT. + :vartype type: str or ~azure.ai.projects.models.FUNCTION_CALL_OUTPUT + :ivar status: The status of the item. Has no effect on the conversation. Is one of the + following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] + :vartype status: str or str or str + :ivar call_id: The ID of the function call this output is for. Required. + :vartype call_id: str + :ivar output: The output of the function call, this is free text and can contain any + information or simply be empty. Required. + :vartype output: str + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + :ivar name: The name of the function that was called. A Foundry extension: OpenAI's + function_call_output does not carry the function name, only ``call_id``. + :vartype name: str """ - endpoints: list["_models.TelemetryEndpoint"] = rest_field( + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the item. This may be provided by the client or generated by the server.""" + object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the API object being returned - always ``realtime.item``. Optional when creating + a new item. Default value is \"realtime.item\".""" + type: Literal[RealtimeConversationItemType.FUNCTION_CALL_OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the item. Always ``function_call_output``. Required. FUNCTION_CALL_OUTPUT.""" + status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Customer-supplied telemetry export endpoint configurations. Required.""" + """The status of the item. Has no effect on the conversation. Is one of the following types: + Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the function call this output is for. Required.""" + output: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The output of the function call, this is free text and can contain any information or simply be + empty. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function that was called. A Foundry extension: OpenAI's function_call_output + does not carry the function name, only ``call_id``.""" @overload def __init__( self, *, - endpoints: list["_models.TelemetryEndpoint"], + call_id: str, + output: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + object: Optional[Literal["realtime.item"]] = None, + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, + name: Optional[str] = None, ) -> None: ... @overload @@ -24288,169 +24687,220 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeConversationItemType.FUNCTION_CALL_OUTPUT # type: ignore -class TelephonyCallJob(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A durable direct or campaign-created outbound call intent. - - :ivar destination: The phone destination to call. Required. - :vartype destination: ~azure.ai.projects.models.TelephonyOutboundDestination - :ivar connection_name: The Foundry connection name in the current project used to originate the - call. Its category selects Twilio or Azure Communication Services / Teams Phone extensibility. - No inbound telephony binding is required. Required. - :vartype connection_name: str - :ivar source: The caller identity used to originate the call. For a Twilio connection, provide - an authorized E.164 phone number. For an Azure Communication Services / Teams Phone - extensibility connection, provide the Teams Resource Account object ID. The identity type is - inferred from the connection category; originating does not change inbound routing. Required. - :vartype source: str - :ivar purpose: An optional customer-declared purpose for placing the call. - :vartype purpose: str - :ivar structured_inputs: Structured input values available to the agent and greeting for this - call. Agent-declared inputs are validated against their schemas; omitted optional inputs may - use their Agent-defined default values, while omitted required inputs are rejected. Additional - inputs remain available as dynamic template variables. - :vartype structured_inputs: dict[str, any] - :ivar schedule: The optional execution window. - :vartype schedule: ~azure.ai.projects.models.TelephonyCallJobSchedule - :ivar id: The service-generated call-job identifier. Required. - :vartype id: str - :ivar object: The object type. Always ``telephony.call_job``. Required. Default value is - "telephony.call_job". - :vartype object: str - :ivar agent_name: The name of the voice agent used at execution time. Required. - :vartype agent_name: str - :ivar status: The current call-job lifecycle status. Required. Known values are: "accepted", - "waiting_for_schedule", "queued", "dispatching", "in_progress", "waiting_for_retry", - "cancellation_requested", "completed", "blocked", "expired", "failed", and "cancelled". - :vartype status: str or ~azure.ai.projects.models.TelephonyCallJobStatus - :ivar cancellation: The recorded cancellation request, when cancellation was requested. - :vartype cancellation: ~azure.ai.projects.models.TelephonyCallJobCancellation - :ivar retry_policy: The frozen provider-attempt retry policy. Required. - :vartype retry_policy: ~azure.ai.projects.models.TelephonyOutboundRetryPolicy - :ivar attempt_count: The number of provider attempts created so far. Required. - :vartype attempt_count: int - :ivar next_attempt_at: The Unix timestamp in seconds at which the next retry becomes eligible. - :vartype next_attempt_at: ~datetime.datetime - :ivar terminal_reason: The stable service-generated reason for the overall outbound call job, - which can span multiple provider attempts, when available. Interpret this with ``status``: a - queued job can retain a temporary dispatch-deferral reason. Additional string codes may be - returned. Known values are: "no_answer", "no_answer_timeout", "answer_failed", - "bridge_cancelled", "bridge_failed", "voice_session_configuration_invalid", - "connection_project_mismatch", "outbound_connection_changed", - "outbound_connection_unavailable", "telephony_binding_invalid", "telephony_binding_not_found", - "telephony_binding_inactive", "telephony_binding_changed", "campaign_not_found", - "campaign_cancelled", "campaign_completed", "campaign_failed", - "origination_fence_not_recorded", "origination_reconciliation_timeout", - "cancellation_reconciliation_timeout", and - "provider_callback_timeout_cancellation_reconciliation_timeout". - :vartype terminal_reason: str or ~azure.ai.projects.models.TelephonyCallJobTerminalReason - :ivar revision: The monotonically increasing optimistic-concurrency revision. Required. - :vartype revision: int - :ivar created_at: The Unix timestamp in seconds when the call job was created. Required. - :vartype created_at: ~datetime.datetime - :ivar updated_at: The Unix timestamp in seconds when the call job was last updated. Required. - :vartype updated_at: ~datetime.datetime - """ +class RealtimeConversationItemMessage( + RealtimeConversationItem, discriminator="message" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeConversationItemMessage. - destination: "_models.TelephonyOutboundDestination" = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The phone destination to call. Required.""" - connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Foundry connection name in the current project used to originate the call. Its category - selects Twilio or Azure Communication Services / Teams Phone extensibility. No inbound - telephony binding is required. Required.""" - source: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The caller identity used to originate the call. For a Twilio connection, provide an authorized - E.164 phone number. For an Azure Communication Services / Teams Phone extensibility connection, - provide the Teams Resource Account object ID. The identity type is inferred from the connection - category; originating does not change inbound routing. Required.""" - purpose: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional customer-declared purpose for placing the call.""" - structured_inputs: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Structured input values available to the agent and greeting for this call. Agent-declared - inputs are validated against their schemas; omitted optional inputs may use their Agent-defined - default values, while omitted required inputs are rejected. Additional inputs remain available - as dynamic template variables.""" - schedule: Optional["_models.TelephonyCallJobSchedule"] = rest_field( + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + RealtimeConversationItemMessageAssistant, RealtimeConversationItemMessageSystem, + RealtimeConversationItemMessageUser + + :ivar role: Required. Known values are: "system", "user", and "assistant". + :vartype role: str or ~azure.ai.projects.models.RealtimeConversationItemMessageType + :ivar type: Required. MESSAGE. + :vartype type: str or ~azure.ai.projects.models.MESSAGE + """ + + __mapping__: dict[str, _Model] = {} + role: str = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"system\", \"user\", and \"assistant\".""" + type: Literal[RealtimeConversationItemType.MESSAGE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. MESSAGE.""" + + @overload + def __init__( + self, + *, + role: 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 = RealtimeConversationItemType.MESSAGE # type: ignore + + +class RealtimeConversationItemMessageAssistant( + RealtimeConversationItemMessage, discriminator="assistant" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime assistant message item. + + :ivar id: The unique ID of the item. This may be provided by the client or generated by the + server. + :vartype id: str + :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional + when creating a new item. Default value is "realtime.item". + :vartype object: str + :ivar type: The type of the item. Always ``message``. Required. MESSAGE. + :vartype type: str or ~azure.ai.projects.models.MESSAGE + :ivar status: The status of the item. Has no effect on the conversation. Is one of the + following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] + :vartype status: str or str or str + :ivar role: The role of the message sender. Always ``assistant``. Required. ASSISTANT. + :vartype role: str or ~azure.ai.projects.models.ASSISTANT + :ivar content: The content of the message. Required. + :vartype content: + list[~azure.ai.projects.models.RealtimeConversationItemMessageAssistantContent] + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the item. This may be provided by the client or generated by the server.""" + object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the API object being returned - always ``realtime.item``. Optional when creating + a new item. Default value is \"realtime.item\".""" + status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The optional execution window.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated call-job identifier. Required.""" - object: Literal["telephony.call_job"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The object type. Always ``telephony.call_job``. Required. Default value is - \"telephony.call_job\".""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the voice agent used at execution time. Required.""" - status: Union[str, "_models.TelephonyCallJobStatus"] = rest_field( + """The status of the item. Has no effect on the conversation. Is one of the following types: + Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" + role: Literal[RealtimeConversationItemMessageType.ASSISTANT] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The role of the message sender. Always ``assistant``. Required. ASSISTANT.""" + content: list["_models.RealtimeConversationItemMessageAssistantContent"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The current call-job lifecycle status. Required. Known values are: \"accepted\", - \"waiting_for_schedule\", \"queued\", \"dispatching\", \"in_progress\", \"waiting_for_retry\", - \"cancellation_requested\", \"completed\", \"blocked\", \"expired\", \"failed\", and - \"cancelled\".""" - cancellation: Optional["_models.TelephonyCallJobCancellation"] = rest_field( + """The content of the message. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" + + @overload + def __init__( + self, + *, + type: Literal[RealtimeConversationItemType.MESSAGE], + content: list["_models.RealtimeConversationItemMessageAssistantContent"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + object: Optional[Literal["realtime.item"]] = None, + status: Optional[Literal["completed", "incomplete", "in_progress"]] = 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.role = RealtimeConversationItemMessageType.ASSISTANT # type: ignore + + +class RealtimeConversationItemMessageAssistantContent( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeConversationItemMessageAssistantContent. + + :ivar type: Is either a Literal["output_text"] type or a Literal["output_audio"] type. + :vartype type: str or str + :ivar text: + :vartype text: str + :ivar audio: + :vartype audio: str + :ivar transcript: + :vartype transcript: str + """ + + type: Optional[Literal["output_text", "output_audio"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The recorded cancellation request, when cancellation was requested.""" - retry_policy: "_models.TelephonyOutboundRetryPolicy" = rest_field( + """Is either a Literal[\"output_text\"] type or a Literal[\"output_audio\"] type.""" + text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + type: Optional[Literal["output_text", "output_audio"]] = None, + text: Optional[str] = None, + audio: Optional[str] = None, + transcript: 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 RealtimeConversationItemMessageSystem( + RealtimeConversationItemMessage, discriminator="system" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime system message item. + + :ivar id: The unique ID of the item. This may be provided by the client or generated by the + server. + :vartype id: str + :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional + when creating a new item. Default value is "realtime.item". + :vartype object: str + :ivar type: The type of the item. Always ``message``. Required. MESSAGE. + :vartype type: str or ~azure.ai.projects.models.MESSAGE + :ivar status: The status of the item. Has no effect on the conversation. Is one of the + following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] + :vartype status: str or str or str + :ivar role: The role of the message sender. Always ``system``. Required. SYSTEM. + :vartype role: str or ~azure.ai.projects.models.SYSTEM + :ivar content: The content of the message. Required. + :vartype content: list[~azure.ai.projects.models.RealtimeConversationItemMessageSystemContent] + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the item. This may be provided by the client or generated by the server.""" + object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the API object being returned - always ``realtime.item``. Optional when creating + a new item. Default value is \"realtime.item\".""" + status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The frozen provider-attempt retry policy. Required.""" - attempt_count: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The number of provider attempts created so far. Required.""" - next_attempt_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp in seconds at which the next retry becomes eligible.""" - terminal_reason: Optional[Union[str, "_models.TelephonyCallJobTerminalReason"]] = rest_field( + """The status of the item. Has no effect on the conversation. Is one of the following types: + Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" + role: Literal[RealtimeConversationItemMessageType.SYSTEM] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The role of the message sender. Always ``system``. Required. SYSTEM.""" + content: list["_models.RealtimeConversationItemMessageSystemContent"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The stable service-generated reason for the overall outbound call job, which can span multiple - provider attempts, when available. Interpret this with ``status``: a queued job can retain a - temporary dispatch-deferral reason. Additional string codes may be returned. Known values are: - \"no_answer\", \"no_answer_timeout\", \"answer_failed\", \"bridge_cancelled\", - \"bridge_failed\", \"voice_session_configuration_invalid\", \"connection_project_mismatch\", - \"outbound_connection_changed\", \"outbound_connection_unavailable\", - \"telephony_binding_invalid\", \"telephony_binding_not_found\", \"telephony_binding_inactive\", - \"telephony_binding_changed\", \"campaign_not_found\", \"campaign_cancelled\", - \"campaign_completed\", \"campaign_failed\", \"origination_fence_not_recorded\", - \"origination_reconciliation_timeout\", \"cancellation_reconciliation_timeout\", and - \"provider_callback_timeout_cancellation_reconciliation_timeout\".""" - revision: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The monotonically increasing optimistic-concurrency revision. Required.""" - created_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp in seconds when the call job was created. Required.""" - updated_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp in seconds when the call job was last updated. Required.""" + """The content of the message. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" @overload def __init__( self, *, - destination: "_models.TelephonyOutboundDestination", - connection_name: str, - source: str, - id: str, # pylint: disable=redefined-builtin - agent_name: str, - status: Union[str, "_models.TelephonyCallJobStatus"], - retry_policy: "_models.TelephonyOutboundRetryPolicy", - attempt_count: int, - revision: int, - created_at: datetime.datetime, - updated_at: datetime.datetime, - purpose: Optional[str] = None, - structured_inputs: Optional[dict[str, Any]] = None, - schedule: Optional["_models.TelephonyCallJobSchedule"] = None, - cancellation: Optional["_models.TelephonyCallJobCancellation"] = None, - next_attempt_at: Optional[datetime.datetime] = None, - terminal_reason: Optional[Union[str, "_models.TelephonyCallJobTerminalReason"]] = None, + type: Literal[RealtimeConversationItemType.MESSAGE], + content: list["_models.RealtimeConversationItemMessageSystemContent"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + object: Optional[Literal["realtime.item"]] = None, + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, ) -> None: ... @overload @@ -24462,41 +24912,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.object: Literal["telephony.call_job"] = "telephony.call_job" + self.role = RealtimeConversationItemMessageType.SYSTEM # type: ignore -class TelephonyCallJobCancellation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A cancellation request recorded for an outbound call job. +class RealtimeConversationItemMessageSystemContent( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeConversationItemMessageSystemContent. - :ivar requested_by: The authenticated principal that requested cancellation. Required. - :vartype requested_by: str - :ivar mode: The cancellation mode applied to the call job. Required. - :vartype mode: str - :ivar requested_at: The Unix timestamp in seconds when cancellation was requested. Required. - :vartype requested_at: ~datetime.datetime - :ivar revision: The call-job revision at which cancellation was recorded. Required. - :vartype revision: int + :ivar type: Default value is "input_text". + :vartype type: str + :ivar text: + :vartype text: str """ - requested_by: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The authenticated principal that requested cancellation. Required.""" - mode: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The cancellation mode applied to the call job. Required.""" - requested_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp in seconds when cancellation was requested. Required.""" - revision: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The call-job revision at which cancellation was recorded. Required.""" + type: Optional[Literal["input_text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Default value is \"input_text\".""" + text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - requested_by: str, - mode: str, - requested_at: datetime.datetime, - revision: int, + type: Optional[Literal["input_text"]] = None, + text: Optional[str] = None, ) -> None: ... @overload @@ -24510,30 +24949,62 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TelephonyCallJobSchedule(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The optional execution window for a direct outbound call. +class RealtimeConversationItemMessageUser( + RealtimeConversationItemMessage, discriminator="user" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime user message item. - :ivar not_before: The earliest instant at which dispatch may begin. - :vartype not_before: ~datetime.datetime - :ivar expires_at: The instant after which the call job expires without dispatch. - :vartype expires_at: ~datetime.datetime + :ivar id: The unique ID of the item. This may be provided by the client or generated by the + server. + :vartype id: str + :ivar object: Identifier for the API object being returned - always ``realtime.item``. Optional + when creating a new item. Default value is "realtime.item". + :vartype object: str + :ivar type: The type of the item. Always ``message``. Required. MESSAGE. + :vartype type: str or ~azure.ai.projects.models.MESSAGE + :ivar status: The status of the item. Has no effect on the conversation. Is one of the + following types: Literal["completed"], Literal["incomplete"], Literal["in_progress"] + :vartype status: str or str or str + :ivar role: The role of the message sender. Always ``user``. Required. USER. + :vartype role: str or ~azure.ai.projects.models.USER + :ivar content: The content of the message. Required. + :vartype content: list[~azure.ai.projects.models.RealtimeConversationItemMessageUserContent] + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str """ - not_before: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the item. This may be provided by the client or generated by the server.""" + object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the API object being returned - always ``realtime.item``. Optional when creating + a new item. Default value is \"realtime.item\".""" + status: Optional[Literal["completed", "incomplete", "in_progress"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The earliest instant at which dispatch may begin.""" - expires_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + """The status of the item. Has no effect on the conversation. Is one of the following types: + Literal[\"completed\"], Literal[\"incomplete\"], Literal[\"in_progress\"]""" + role: Literal[RealtimeConversationItemMessageType.USER] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The role of the message sender. Always ``user``. Required. USER.""" + content: list["_models.RealtimeConversationItemMessageUserContent"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The instant after which the call job expires without dispatch.""" + """The content of the message. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" @overload def __init__( self, *, - not_before: Optional[datetime.datetime] = None, - expires_at: Optional[datetime.datetime] = None, + type: Literal[RealtimeConversationItemType.MESSAGE], + content: list["_models.RealtimeConversationItemMessageUserContent"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + object: Optional[Literal["realtime.item"]] = None, + status: Optional[Literal["completed", "incomplete", "in_progress"]] = None, ) -> None: ... @overload @@ -24545,129 +25016,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.role = RealtimeConversationItemMessageType.USER # type: ignore -class TelephonyCallLifecycleEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A bounded durable observation in the lifecycle of one telephony call. +class RealtimeConversationItemMessageUserContent( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeConversationItemMessageUserContent. - :ivar sequence: The service-assigned order of the event within the call record. Required. - :vartype sequence: int - :ivar name: The stable provider-neutral event name. Required. Known values are: - "telephony.webhook.received", "telephony.webhook.validation", "telephony.binding.resolve", - "telephony.provider.answer", "telephony.media.connect", "telephony.agent_session.connect", - "telephony.media.first_caller_audio", "telephony.media.first_agent_audio", - "telephony.call.transfer", "telephony.call.hangup", and "telephony.call.disconnect". - :vartype name: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventName - :ivar source: The component that supplied the observation. Required. Known values are: - "gateway", "teams_phone_extensibility", "twilio", and "voice_agent". - :vartype source: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventSource - :ivar outcome: The outcome of the observed lifecycle operation. Required. Known values are: - "observed", "started", "succeeded", "failed", "rejected", and "cancelled". - :vartype outcome: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventOutcome - :ivar observed_at: The Unix timestamp (in seconds) for when the service observed the event. - Required. - :vartype observed_at: ~datetime.datetime - :ivar occurred_at: The Unix timestamp (in seconds) for when the event occurred according to the - provider. - :vartype occurred_at: ~datetime.datetime - :ivar timestamp_source: The source of the event timestamp. Required. Known values are: - "provider", "gateway", and "derived". - :vartype timestamp_source: str or ~azure.ai.projects.models.TelephonyCallTimestampSource - :ivar reason: A stable service-generated reason associated with this lifecycle event, not - necessarily the final outcome of the call. Additional string codes may be returned. Known - values are: "invalid_webhook_payload", "webhook_validation_failed", "binding_not_found", - "binding_suspended", "admission_rejected", "admission_check_failed", "route_agent_mismatch", - "invalid_binding_configuration", "credential_resolution_failed", "provider_resource_mismatch", - "endpoint_resolution_failed", "ingress_setup_failed", "live_call_conflict", - "live_call_persistence_failed", "answer_failed", "provider_disconnected", "provider_busy", - "provider_no_answer", "provider_cancelled", "provider_failed", "provider_stream_error", - "provider_stream_stopped", "agent_session_connect_failed", "media_stream_ended", - "bridge_cancelled", "bridge_failed", "managed_hangup", "managed_transfer", - "manage_hangup_failed", and "manage_transfer_failed". - :vartype reason: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventReason - :ivar provider_event_id: The provider event identifier used for idempotency, when supplied. - :vartype provider_event_id: str - :ivar provider_sequence: The provider event sequence, when supplied. - :vartype provider_sequence: int - :ivar provider_status_code: The provider status code associated with the event. - :vartype provider_status_code: int - :ivar provider_sub_code: The provider subcode associated with the event. - :vartype provider_sub_code: int + :ivar type: Is one of the following types: Literal["input_text"], Literal["input_audio"], + Literal["input_image"] + :vartype type: str or str or str + :ivar text: + :vartype text: str + :ivar audio: + :vartype audio: str + :ivar image_url: + :vartype image_url: str + :ivar detail: Is one of the following types: Literal["auto"], Literal["low"], Literal["high"] + :vartype detail: str or str or str + :ivar transcript: + :vartype transcript: str """ - sequence: int = rest_field(visibility=["read"]) - """The service-assigned order of the event within the call record. Required.""" - name: Union[str, "_models.TelephonyCallLifecycleEventName"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The stable provider-neutral event name. Required. Known values are: - \"telephony.webhook.received\", \"telephony.webhook.validation\", - \"telephony.binding.resolve\", \"telephony.provider.answer\", \"telephony.media.connect\", - \"telephony.agent_session.connect\", \"telephony.media.first_caller_audio\", - \"telephony.media.first_agent_audio\", \"telephony.call.transfer\", \"telephony.call.hangup\", - and \"telephony.call.disconnect\".""" - source: Union[str, "_models.TelephonyCallLifecycleEventSource"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The component that supplied the observation. Required. Known values are: \"gateway\", - \"teams_phone_extensibility\", \"twilio\", and \"voice_agent\".""" - outcome: Union[str, "_models.TelephonyCallLifecycleEventOutcome"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The outcome of the observed lifecycle operation. Required. Known values are: \"observed\", - \"started\", \"succeeded\", \"failed\", \"rejected\", and \"cancelled\".""" - observed_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the service observed the event. Required.""" - occurred_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the event occurred according to the provider.""" - timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"] = rest_field( + type: Optional[Literal["input_text", "input_audio", "input_image"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The source of the event timestamp. Required. Known values are: \"provider\", \"gateway\", and - \"derived\".""" - reason: Optional[Union[str, "_models.TelephonyCallLifecycleEventReason"]] = rest_field( + """Is one of the following types: Literal[\"input_text\"], Literal[\"input_audio\"], + Literal[\"input_image\"]""" + text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + image_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + detail: Optional[Literal["auto", "low", "high"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """A stable service-generated reason associated with this lifecycle event, not necessarily the - final outcome of the call. Additional string codes may be returned. Known values are: - \"invalid_webhook_payload\", \"webhook_validation_failed\", \"binding_not_found\", - \"binding_suspended\", \"admission_rejected\", \"admission_check_failed\", - \"route_agent_mismatch\", \"invalid_binding_configuration\", \"credential_resolution_failed\", - \"provider_resource_mismatch\", \"endpoint_resolution_failed\", \"ingress_setup_failed\", - \"live_call_conflict\", \"live_call_persistence_failed\", \"answer_failed\", - \"provider_disconnected\", \"provider_busy\", \"provider_no_answer\", \"provider_cancelled\", - \"provider_failed\", \"provider_stream_error\", \"provider_stream_stopped\", - \"agent_session_connect_failed\", \"media_stream_ended\", \"bridge_cancelled\", - \"bridge_failed\", \"managed_hangup\", \"managed_transfer\", \"manage_hangup_failed\", and - \"manage_transfer_failed\".""" - provider_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider event identifier used for idempotency, when supplied.""" - provider_sequence: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider event sequence, when supplied.""" - provider_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider status code associated with the event.""" - provider_sub_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider subcode associated with the event.""" + """Is one of the following types: Literal[\"auto\"], Literal[\"low\"], Literal[\"high\"]""" + transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - name: Union[str, "_models.TelephonyCallLifecycleEventName"], - source: Union[str, "_models.TelephonyCallLifecycleEventSource"], - outcome: Union[str, "_models.TelephonyCallLifecycleEventOutcome"], - observed_at: datetime.datetime, - timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"], - occurred_at: Optional[datetime.datetime] = None, - reason: Optional[Union[str, "_models.TelephonyCallLifecycleEventReason"]] = None, - provider_event_id: Optional[str] = None, - provider_sequence: Optional[int] = None, - provider_status_code: Optional[int] = None, - provider_sub_code: Optional[int] = None, + type: Optional[Literal["input_text", "input_audio", "input_image"]] = None, + text: Optional[str] = None, + audio: Optional[str] = None, + image_url: Optional[str] = None, + detail: Optional[Literal["auto", "low", "high"]] = None, + transcript: Optional[str] = None, ) -> None: ... @overload @@ -24681,180 +25076,102 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TelephonyCallRecord(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Detailed diagnostics for a durable inbound call to a voice agent. +class RealtimeFunctionTool(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Function tool. - :ivar id: The service-generated call identifier. Required. - :vartype id: str - :ivar provider: The telephony provider. Required. Known values are: "teams_phone_extensibility" - and "twilio". - :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider - :ivar provider_call_id: The provider-assigned call identifier, when available. - :vartype provider_call_id: str - :ivar caller_number: The caller's phone number, when supplied by the provider. - :vartype caller_number: str - :ivar provider_number: The Teams Phone extensibility or Twilio number that received the call. - :vartype provider_number: str - :ivar status: The lifecycle status of the call. Required. Known values are: "in_progress", - "success", and "failed". - :vartype status: str or ~azure.ai.projects.models.TelephonyCallStatus - :ivar phase: The provider-neutral lifecycle phase reached by the call. Required. Known values - are: "received", "validated", "admitted", "answering", "answered", "media_connected", - "agent_session_ready", "bridging", "managing", "completed", "rejected", and "failed". - :vartype phase: str or ~azure.ai.projects.models.TelephonyCallPhase - :ivar started_at: The Unix timestamp (in seconds) for when the inbound webhook was received. - Required. - :vartype started_at: ~datetime.datetime - :ivar answered_at: The Unix timestamp (in seconds) for when the provider reported the call as - answered. - :vartype answered_at: ~datetime.datetime - :ivar media_connected_at: The Unix timestamp (in seconds) for when the provider media channel - connected. - :vartype media_connected_at: ~datetime.datetime - :ivar agent_session_ready_at: The Unix timestamp (in seconds) for when the voice-agent session - became ready. - :vartype agent_session_ready_at: ~datetime.datetime - :ivar ended_at: The Unix timestamp (in seconds) for when the call ended. - :vartype ended_at: ~datetime.datetime - :ivar duration_ms: The call duration. - :vartype duration_ms: ~datetime.timedelta - :ivar end_reason: The service-generated reason that this single call ended, rather than the - outcome of an overall outbound call job. Additional string codes may be returned. Known values - are: "invalid_webhook_payload", "webhook_validation_failed", "binding_not_found", - "binding_suspended", "admission_rejected", "admission_check_failed", "route_agent_mismatch", - "invalid_binding_configuration", "credential_resolution_failed", "provider_resource_mismatch", - "endpoint_resolution_failed", "ingress_setup_failed", "live_call_conflict", - "live_call_persistence_failed", "answer_failed", "provider_disconnected", "provider_busy", - "provider_no_answer", "provider_cancelled", "provider_failed", "provider_stream_error", - "provider_stream_stopped", "agent_session_connect_failed", "media_stream_ended", - "bridge_cancelled", "bridge_failed", "managed_hangup", "managed_transfer", - "manage_hangup_failed", and "manage_transfer_failed". - :vartype end_reason: str or ~azure.ai.projects.models.TelephonyCallEndReason - :ivar provider_status_code: The provider status code associated with the terminal result. - :vartype provider_status_code: int - :ivar provider_sub_code: The provider subcode associated with the terminal result. - :vartype provider_sub_code: int - :ivar provider_message: The provider message associated with the terminal result. - :vartype provider_message: str - :ivar timing: Detailed provider-neutral call timing. Required. - :vartype timing: ~azure.ai.projects.models.TelephonyCallTiming - :ivar trace: Correlation to the customer-facing Foundry trace. - :vartype trace: ~azure.ai.projects.models.TelephonyCallTrace - :ivar events: The lifecycle timeline. Required. - :vartype events: list[~azure.ai.projects.models.TelephonyCallLifecycleEvent] - :ivar events_truncated: Whether older lifecycle events were omitted from the timeline. - Required. - :vartype events_truncated: bool + :ivar type: The type of the tool, i.e. ``function``. Default value is "function". + :vartype type: str + :ivar name: The name of the function. + :vartype name: str + :ivar description: The description of the function, including guidance on when and how to call + it, and guidance about what to tell the user when calling (if anything). + :vartype description: str + :ivar parameters: Parameters of the function in JSON Schema. + :vartype parameters: ~azure.ai.projects.models.RealtimeFunctionToolParameters """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated call identifier. Required.""" - provider: Union[str, "_models.TelephonyProvider"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The telephony provider. Required. Known values are: \"teams_phone_extensibility\" and - \"twilio\".""" - provider_call_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider-assigned call identifier, when available.""" - caller_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The caller's phone number, when supplied by the provider.""" - provider_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Teams Phone extensibility or Twilio number that received the call.""" - status: Union[str, "_models.TelephonyCallStatus"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The lifecycle status of the call. Required. Known values are: \"in_progress\", \"success\", and - \"failed\".""" - phase: Union[str, "_models.TelephonyCallPhase"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The provider-neutral lifecycle phase reached by the call. Required. Known values are: - \"received\", \"validated\", \"admitted\", \"answering\", \"answered\", \"media_connected\", - \"agent_session_ready\", \"bridging\", \"managing\", \"completed\", \"rejected\", and - \"failed\".""" - started_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the inbound webhook was received. Required.""" - answered_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider reported the call as answered.""" - media_connected_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider media channel connected.""" - agent_session_ready_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the voice-agent session became ready.""" - ended_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the call ended.""" - duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """The call duration.""" - end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The service-generated reason that this single call ended, rather than the outcome of an overall - outbound call job. Additional string codes may be returned. Known values are: - \"invalid_webhook_payload\", \"webhook_validation_failed\", \"binding_not_found\", - \"binding_suspended\", \"admission_rejected\", \"admission_check_failed\", - \"route_agent_mismatch\", \"invalid_binding_configuration\", \"credential_resolution_failed\", - \"provider_resource_mismatch\", \"endpoint_resolution_failed\", \"ingress_setup_failed\", - \"live_call_conflict\", \"live_call_persistence_failed\", \"answer_failed\", - \"provider_disconnected\", \"provider_busy\", \"provider_no_answer\", \"provider_cancelled\", - \"provider_failed\", \"provider_stream_error\", \"provider_stream_stopped\", - \"agent_session_connect_failed\", \"media_stream_ended\", \"bridge_cancelled\", - \"bridge_failed\", \"managed_hangup\", \"managed_transfer\", \"manage_hangup_failed\", and - \"manage_transfer_failed\".""" - provider_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider status code associated with the terminal result.""" - provider_sub_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider subcode associated with the terminal result.""" - provider_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider message associated with the terminal result.""" - timing: "_models.TelephonyCallTiming" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Detailed provider-neutral call timing. Required.""" - trace: Optional["_models.TelephonyCallTrace"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Correlation to the customer-facing Foundry trace.""" - events: list["_models.TelephonyCallLifecycleEvent"] = rest_field( + type: Optional[Literal["function"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The type of the tool, i.e. ``function``. Default value is \"function\".""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The description of the function, including guidance on when and how to call it, and guidance + about what to tell the user when calling (if anything).""" + parameters: Optional["_models.RealtimeFunctionToolParameters"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The lifecycle timeline. Required.""" - events_truncated: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether older lifecycle events were omitted from the timeline. Required.""" + """Parameters of the function in JSON Schema.""" + + @overload + def __init__( + self, + *, + type: Optional[Literal["function"]] = None, + name: Optional[str] = None, + description: Optional[str] = None, + parameters: Optional["_models.RealtimeFunctionToolParameters"] = 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 RealtimeFunctionToolParameters(_Model): + """RealtimeFunctionToolParameters.""" + + +class RealtimeMCPApprovalRequest( + RealtimeConversationItem, discriminator="mcp_approval_request" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP approval request. + + :ivar type: The type of the item. Always ``mcp_approval_request``. Required. + MCP_APPROVAL_REQUEST. + :vartype type: str or ~azure.ai.projects.models.MCP_APPROVAL_REQUEST + :ivar id: The unique ID of the approval request. Required. + :vartype id: str + :ivar server_label: The label of the MCP server making the request. Required. + :vartype server_label: str + :ivar name: The name of the tool to run. Required. + :vartype name: str + :ivar arguments: A JSON string of arguments for the tool. Required. + :vartype arguments: str + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + """ + + type: Literal[RealtimeConversationItemType.MCP_APPROVAL_REQUEST] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the item. Always ``mcp_approval_request``. Required. MCP_APPROVAL_REQUEST.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the approval request. Required.""" + server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The label of the MCP server making the request. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the tool to run. Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A JSON string of arguments for the tool. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" @overload def __init__( self, *, id: str, # pylint: disable=redefined-builtin - provider: Union[str, "_models.TelephonyProvider"], - status: Union[str, "_models.TelephonyCallStatus"], - phase: Union[str, "_models.TelephonyCallPhase"], - started_at: datetime.datetime, - timing: "_models.TelephonyCallTiming", - events: list["_models.TelephonyCallLifecycleEvent"], - events_truncated: bool, - provider_call_id: Optional[str] = None, - caller_number: Optional[str] = None, - provider_number: Optional[str] = None, - answered_at: Optional[datetime.datetime] = None, - media_connected_at: Optional[datetime.datetime] = None, - agent_session_ready_at: Optional[datetime.datetime] = None, - ended_at: Optional[datetime.datetime] = None, - duration_ms: Optional[datetime.timedelta] = None, - end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = None, - provider_status_code: Optional[int] = None, - provider_sub_code: Optional[int] = None, - provider_message: Optional[str] = None, - trace: Optional["_models.TelephonyCallTrace"] = None, + server_label: str, + name: str, + arguments: str, ) -> None: ... @overload @@ -24866,157 +25183,53 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeConversationItemType.MCP_APPROVAL_REQUEST # type: ignore -class TelephonyCallSummary(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A summary of a durable inbound call to a voice agent. +class RealtimeMCPApprovalResponse( + RealtimeConversationItem, discriminator="mcp_approval_response" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP approval response. - :ivar id: The service-generated call identifier. Required. + :ivar type: The type of the item. Always ``mcp_approval_response``. Required. + MCP_APPROVAL_RESPONSE. + :vartype type: str or ~azure.ai.projects.models.MCP_APPROVAL_RESPONSE + :ivar id: The unique ID of the approval response. Required. :vartype id: str - :ivar provider: The telephony provider. Required. Known values are: "teams_phone_extensibility" - and "twilio". - :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider - :ivar provider_call_id: The provider-assigned call identifier, when available. - :vartype provider_call_id: str - :ivar caller_number: The caller's phone number, when supplied by the provider. - :vartype caller_number: str - :ivar provider_number: The Teams Phone extensibility or Twilio number that received the call. - :vartype provider_number: str - :ivar status: The lifecycle status of the call. Required. Known values are: "in_progress", - "success", and "failed". - :vartype status: str or ~azure.ai.projects.models.TelephonyCallStatus - :ivar phase: The provider-neutral lifecycle phase reached by the call. Required. Known values - are: "received", "validated", "admitted", "answering", "answered", "media_connected", - "agent_session_ready", "bridging", "managing", "completed", "rejected", and "failed". - :vartype phase: str or ~azure.ai.projects.models.TelephonyCallPhase - :ivar started_at: The Unix timestamp (in seconds) for when the inbound webhook was received. - Required. - :vartype started_at: ~datetime.datetime - :ivar answered_at: The Unix timestamp (in seconds) for when the provider reported the call as - answered. - :vartype answered_at: ~datetime.datetime - :ivar media_connected_at: The Unix timestamp (in seconds) for when the provider media channel - connected. - :vartype media_connected_at: ~datetime.datetime - :ivar agent_session_ready_at: The Unix timestamp (in seconds) for when the voice-agent session - became ready. - :vartype agent_session_ready_at: ~datetime.datetime - :ivar ended_at: The Unix timestamp (in seconds) for when the call ended. - :vartype ended_at: ~datetime.datetime - :ivar duration_ms: The call duration. - :vartype duration_ms: ~datetime.timedelta - :ivar end_reason: The service-generated reason that this single call ended, rather than the - outcome of an overall outbound call job. Additional string codes may be returned. Known values - are: "invalid_webhook_payload", "webhook_validation_failed", "binding_not_found", - "binding_suspended", "admission_rejected", "admission_check_failed", "route_agent_mismatch", - "invalid_binding_configuration", "credential_resolution_failed", "provider_resource_mismatch", - "endpoint_resolution_failed", "ingress_setup_failed", "live_call_conflict", - "live_call_persistence_failed", "answer_failed", "provider_disconnected", "provider_busy", - "provider_no_answer", "provider_cancelled", "provider_failed", "provider_stream_error", - "provider_stream_stopped", "agent_session_connect_failed", "media_stream_ended", - "bridge_cancelled", "bridge_failed", "managed_hangup", "managed_transfer", - "manage_hangup_failed", and "manage_transfer_failed". - :vartype end_reason: str or ~azure.ai.projects.models.TelephonyCallEndReason - :ivar provider_status_code: The provider status code associated with the terminal result. - :vartype provider_status_code: int - :ivar provider_sub_code: The provider subcode associated with the terminal result. - :vartype provider_sub_code: int - :ivar provider_message: The provider message associated with the terminal result. - :vartype provider_message: str + :ivar approval_request_id: The ID of the approval request being answered. Required. + :vartype approval_request_id: str + :ivar approve: Whether the request was approved. Required. + :vartype approve: bool + :ivar reason: + :vartype reason: str + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str """ + type: Literal[RealtimeConversationItemType.MCP_APPROVAL_RESPONSE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the item. Always ``mcp_approval_response``. Required. MCP_APPROVAL_RESPONSE.""" id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The service-generated call identifier. Required.""" - provider: Union[str, "_models.TelephonyProvider"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The telephony provider. Required. Known values are: \"teams_phone_extensibility\" and - \"twilio\".""" - provider_call_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider-assigned call identifier, when available.""" - caller_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The caller's phone number, when supplied by the provider.""" - provider_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Teams Phone extensibility or Twilio number that received the call.""" - status: Union[str, "_models.TelephonyCallStatus"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The lifecycle status of the call. Required. Known values are: \"in_progress\", \"success\", and - \"failed\".""" - phase: Union[str, "_models.TelephonyCallPhase"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The provider-neutral lifecycle phase reached by the call. Required. Known values are: - \"received\", \"validated\", \"admitted\", \"answering\", \"answered\", \"media_connected\", - \"agent_session_ready\", \"bridging\", \"managing\", \"completed\", \"rejected\", and - \"failed\".""" - started_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the inbound webhook was received. Required.""" - answered_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider reported the call as answered.""" - media_connected_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider media channel connected.""" - agent_session_ready_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the voice-agent session became ready.""" - ended_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the call ended.""" - duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """The call duration.""" - end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The service-generated reason that this single call ended, rather than the outcome of an overall - outbound call job. Additional string codes may be returned. Known values are: - \"invalid_webhook_payload\", \"webhook_validation_failed\", \"binding_not_found\", - \"binding_suspended\", \"admission_rejected\", \"admission_check_failed\", - \"route_agent_mismatch\", \"invalid_binding_configuration\", \"credential_resolution_failed\", - \"provider_resource_mismatch\", \"endpoint_resolution_failed\", \"ingress_setup_failed\", - \"live_call_conflict\", \"live_call_persistence_failed\", \"answer_failed\", - \"provider_disconnected\", \"provider_busy\", \"provider_no_answer\", \"provider_cancelled\", - \"provider_failed\", \"provider_stream_error\", \"provider_stream_stopped\", - \"agent_session_connect_failed\", \"media_stream_ended\", \"bridge_cancelled\", - \"bridge_failed\", \"managed_hangup\", \"managed_transfer\", \"manage_hangup_failed\", and - \"manage_transfer_failed\".""" - provider_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider status code associated with the terminal result.""" - provider_sub_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider subcode associated with the terminal result.""" - provider_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The provider message associated with the terminal result.""" + """The unique ID of the approval response. Required.""" + approval_request_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the approval request being answered. Required.""" + approve: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the request was approved. Required.""" + reason: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" @overload def __init__( self, *, id: str, # pylint: disable=redefined-builtin - provider: Union[str, "_models.TelephonyProvider"], - status: Union[str, "_models.TelephonyCallStatus"], - phase: Union[str, "_models.TelephonyCallPhase"], - started_at: datetime.datetime, - provider_call_id: Optional[str] = None, - caller_number: Optional[str] = None, - provider_number: Optional[str] = None, - answered_at: Optional[datetime.datetime] = None, - media_connected_at: Optional[datetime.datetime] = None, - agent_session_ready_at: Optional[datetime.datetime] = None, - ended_at: Optional[datetime.datetime] = None, - duration_ms: Optional[datetime.timedelta] = None, - end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = None, - provider_status_code: Optional[int] = None, - provider_sub_code: Optional[int] = None, - provider_message: Optional[str] = None, + approval_request_id: str, + approve: bool, + reason: Optional[str] = None, ) -> None: ... @overload @@ -25028,115 +25241,8978 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = RealtimeConversationItemType.MCP_APPROVAL_RESPONSE # type: ignore -class TelephonyCallTiming(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Detailed provider-neutral timing for an inbound telephony call. +class RealtimeMCPError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeMCPError. - :ivar received_at: The Unix timestamp (in seconds) for when the provider webhook was received. - :vartype received_at: ~datetime.datetime - :ivar validated_at: The Unix timestamp (in seconds) for when webhook validation completed. - :vartype validated_at: ~datetime.datetime - :ivar admitted_at: The Unix timestamp (in seconds) for when the call was admitted to an agent - binding. - :vartype admitted_at: ~datetime.datetime - :ivar answer_requested_at: The Unix timestamp (in seconds) for when the service requested that - the provider answer the call. - :vartype answer_requested_at: ~datetime.datetime - :ivar answered_at: The Unix timestamp (in seconds) for when the provider reported that the call - was answered. - :vartype answered_at: ~datetime.datetime - :ivar media_connected_at: The Unix timestamp (in seconds) for when the provider media channel - connected. - :vartype media_connected_at: ~datetime.datetime - :ivar agent_session_ready_at: The Unix timestamp (in seconds) for when the voice-agent session - became ready. - :vartype agent_session_ready_at: ~datetime.datetime - :ivar first_caller_audio_at: The Unix timestamp (in seconds) for when caller audio was first - observed. - :vartype first_caller_audio_at: ~datetime.datetime - :ivar first_agent_audio_at: The Unix timestamp (in seconds) for when agent audio was first - observed. - :vartype first_agent_audio_at: ~datetime.datetime - :ivar ended_at: The Unix timestamp (in seconds) for when the call reached a terminal state. - :vartype ended_at: ~datetime.datetime - :ivar duration_basis: The timestamp used as the basis for duration. Known values are: - "answered" and "received". - :vartype duration_basis: str or ~azure.ai.projects.models.TelephonyCallDurationBasis - :ivar timestamp_source: The primary source of the timing milestones. Individual lifecycle - events identify their own timestamp source separately. Required. Known values are: "provider", - "gateway", and "derived". - :vartype timestamp_source: str or ~azure.ai.projects.models.TelephonyCallTimestampSource + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + RealtimeMCPHTTPError, RealtimeMCPProtocolError, RealtimeMCPToolExecutionError + + :ivar type: Required. Known values are: "protocol_error", "tool_execution_error", and + "http_error". + :vartype type: str or ~azure.ai.projects.models.RealtimeMcpErrorType """ - received_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider webhook was received.""" - validated_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when webhook validation completed.""" - admitted_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the call was admitted to an agent binding.""" - answer_requested_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the service requested that the provider answer the - call.""" - answered_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider reported that the call was answered.""" - media_connected_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the provider media channel connected.""" - agent_session_ready_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the voice-agent session became ready.""" - first_caller_audio_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when caller audio was first observed.""" - first_agent_audio_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when agent audio was first observed.""" - ended_at: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (in seconds) for when the call reached a terminal state.""" - duration_basis: Optional[Union[str, "_models.TelephonyCallDurationBasis"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The timestamp used as the basis for duration. Known values are: \"answered\" and \"received\".""" - timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The primary source of the timing milestones. Individual lifecycle events identify their own - timestamp source separately. Required. Known values are: \"provider\", \"gateway\", and - \"derived\".""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"protocol_error\", \"tool_execution_error\", and \"http_error\".""" + + @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 RealtimeMCPHTTPError( + RealtimeMCPError, discriminator="http_error" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP HTTP error. + + :ivar type: Required. HTTP_ERROR. + :vartype type: str or ~azure.ai.projects.models.HTTP_ERROR + :ivar code: Required. + :vartype code: int + :ivar message: Required. + :vartype message: str + """ + + type: Literal[RealtimeMcpErrorType.HTTP_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. HTTP_ERROR.""" + code: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + code: int, + message: 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 = RealtimeMcpErrorType.HTTP_ERROR # type: ignore + + +class RealtimeMCPListTools( + RealtimeConversationItem, discriminator="mcp_list_tools" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP list tools. + + :ivar type: The type of the item. Always ``mcp_list_tools``. Required. MCP_LIST_TOOLS. + :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS + :ivar id: The unique ID of the list. + :vartype id: str + :ivar server_label: The label of the MCP server. Required. + :vartype server_label: str + :ivar tools: The tools available on the server. Required. + :vartype tools: list[~azure.ai.projects.models.MCPListToolsTool] + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + """ + + type: Literal[RealtimeConversationItemType.MCP_LIST_TOOLS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the item. Always ``mcp_list_tools``. Required. MCP_LIST_TOOLS.""" + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the list.""" + server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The label of the MCP server. Required.""" + tools: list["_models.MCPListToolsTool"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The tools available on the server. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" + + @overload + def __init__( + self, + *, + server_label: str, + tools: list["_models.MCPListToolsTool"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + ) -> 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 = RealtimeConversationItemType.MCP_LIST_TOOLS # type: ignore + + +class RealtimeMCPProtocolError( + RealtimeMCPError, discriminator="protocol_error" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP protocol error. + + :ivar type: Required. PROTOCOL_ERROR. + :vartype type: str or ~azure.ai.projects.models.PROTOCOL_ERROR + :ivar code: Required. + :vartype code: int + :ivar message: Required. + :vartype message: str + """ + + type: Literal[RealtimeMcpErrorType.PROTOCOL_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. PROTOCOL_ERROR.""" + code: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + code: int, + message: 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 = RealtimeMcpErrorType.PROTOCOL_ERROR # type: ignore + + +class RealtimeMCPToolCall( + RealtimeConversationItem, discriminator="mcp_call" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP tool call. + + :ivar type: The type of the item. Always ``mcp_call``. Required. MCP_CALL. + :vartype type: str or ~azure.ai.projects.models.MCP_CALL + :ivar id: The unique ID of the tool call. Required. + :vartype id: str + :ivar server_label: The label of the MCP server running the tool. Required. + :vartype server_label: str + :ivar name: The name of the tool that was run. Required. + :vartype name: str + :ivar arguments: A JSON string of the arguments passed to the tool. Required. + :vartype arguments: str + :ivar approval_request_id: + :vartype approval_request_id: str + :ivar output: + :vartype output: str + :ivar error: + :vartype error: ~azure.ai.projects.models.RealtimeMCPError + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + """ + + type: Literal[RealtimeConversationItemType.MCP_CALL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the item. Always ``mcp_call``. Required. MCP_CALL.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the tool call. Required.""" + server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The label of the MCP server running the tool. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the tool that was run. Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A JSON string of the arguments passed to the tool. Required.""" + approval_request_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + output: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + error: Optional["_models.RealtimeMCPError"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + server_label: str, + name: str, + arguments: str, + approval_request_id: Optional[str] = None, + output: Optional[str] = None, + error: Optional["_models.RealtimeMCPError"] = 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 = RealtimeConversationItemType.MCP_CALL # type: ignore + + +class RealtimeMCPToolExecutionError( + RealtimeMCPError, discriminator="tool_execution_error" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime MCP tool execution error. + + :ivar type: Required. TOOL_EXECUTION_ERROR. + :vartype type: str or ~azure.ai.projects.models.TOOL_EXECUTION_ERROR + :ivar message: Required. + :vartype message: str + """ + + type: Literal[RealtimeMcpErrorType.TOOL_EXECUTION_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. TOOL_EXECUTION_ERROR.""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + message: 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 = RealtimeMcpErrorType.TOOL_EXECUTION_ERROR # type: ignore + + +class RealtimeReasoning(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime reasoning configuration. + + :ivar effort: Known values are: "minimal", "low", "medium", "high", and "xhigh". + :vartype effort: str or ~azure.ai.projects.models.RealtimeReasoningEffort + """ + + effort: Optional[Union[str, "_models.RealtimeReasoningEffort"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"minimal\", \"low\", \"medium\", \"high\", and \"xhigh\".""" + + @overload + def __init__( + self, + *, + effort: Optional[Union[str, "_models.RealtimeReasoningEffort"]] = 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 RealtimeResponseInputAudio(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input audio. + + :ivar type: Required. Default value is "input_audio". + :vartype type: str + :ivar audio: Base64 audio bytes in the session input audio format. Required. + :vartype audio: str + :ivar transcript: Optional text to associate with the input audio. + :vartype transcript: str + """ + + type: Literal["input_audio"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"input_audio\".""" + audio: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base64 audio bytes in the session input audio format. Required.""" + transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional text to associate with the input audio.""" + + @overload + def __init__( + self, + *, + audio: str, + transcript: 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: Literal["input_audio"] = "input_audio" + + +class RealtimeResponseInputFunctionCall(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input function call. + + :ivar id: + :vartype id: str + :ivar type: Required. Default value is "function_call". + :vartype type: str + :ivar status: Is either a Literal["completed"] type or a Literal["incomplete"] type. + :vartype status: str or str + :ivar call_id: Required. + :vartype call_id: str + :ivar name: Required. + :vartype name: str + :ivar arguments: Required. + :vartype arguments: str + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal["function_call"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"function_call\".""" + status: Optional[Literal["completed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is either a Literal[\"completed\"] type or a Literal[\"incomplete\"] type.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + call_id: str, + name: str, + arguments: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Literal["completed", "incomplete"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["function_call"] = "function_call" + + +class RealtimeResponseInputFunctionCallOutput(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input function call output. + + :ivar id: + :vartype id: str + :ivar type: Required. Default value is "function_call_output". + :vartype type: str + :ivar status: Is either a Literal["completed"] type or a Literal["incomplete"] type. + :vartype status: str or str + :ivar call_id: Required. + :vartype call_id: str + :ivar output: Required. + :vartype output: str + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Literal["function_call_output"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"function_call_output\".""" + status: Optional[Literal["completed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is either a Literal[\"completed\"] type or a Literal[\"incomplete\"] type.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + output: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + call_id: str, + output: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Literal["completed", "incomplete"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["function_call_output"] = "function_call_output" + + +class RealtimeResponseInputImage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input image. + + :ivar type: Required. Default value is "input_image". + :vartype type: str + :ivar image_url: A base64 data URL with an image MIME type; use PNG or JPEG. Required. + :vartype image_url: str + :ivar detail: Is one of the following types: Literal["low"], Literal["high"], Literal["auto"] + :vartype detail: str or str or str + """ + + type: Literal["input_image"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"input_image\".""" + image_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A base64 data URL with an image MIME type; use PNG or JPEG. Required.""" + detail: Optional[Literal["low", "high", "auto"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is one of the following types: Literal[\"low\"], Literal[\"high\"], Literal[\"auto\"]""" + + @overload + def __init__( + self, + *, + image_url: str, + detail: Optional[Literal["low", "high", "auto"]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["input_image"] = "input_image" + + +class RealtimeResponseInputMessage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input message. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + RealtimeResponseInputMessageAssistant, RealtimeResponseInputMessageDeveloper, + RealtimeResponseInputMessageSystem, RealtimeResponseInputMessageUser + + :ivar role: Required. Known values are: "system", "developer", "user", and "assistant". + :vartype role: str or ~azure.ai.projects.models.RealtimeResponseInputMessageType + """ + + __mapping__: dict[str, _Model] = {} + role: str = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"system\", \"developer\", \"user\", and \"assistant\".""" + + @overload + def __init__( + self, + *, + role: 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 RealtimeResponseInputMessageAssistant( + RealtimeResponseInputMessage, discriminator="assistant" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input assistant message. + + :ivar id: An optional client ID. The value ``root`` is reserved. + :vartype id: str + :ivar type: Required. Default value is "message". + :vartype type: str + :ivar status: Optional input status. Omission or null defaults to completed. Is either a + Literal["completed"] type or a Literal["incomplete"] type. + :vartype status: str or str + :ivar role: Required. ASSISTANT. + :vartype role: str or ~azure.ai.projects.models.ASSISTANT + :ivar content: Required. + :vartype content: list[~azure.ai.projects.models.RealtimeResponseInputMessageAssistantContent] + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional client ID. The value ``root`` is reserved.""" + type: Literal["message"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"message\".""" + status: Optional[Literal["completed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional input status. Omission or null defaults to completed. Is either a + Literal[\"completed\"] type or a Literal[\"incomplete\"] type.""" + role: Literal[RealtimeResponseInputMessageType.ASSISTANT] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. ASSISTANT.""" + content: list["_models.RealtimeResponseInputMessageAssistantContent"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + + @overload + def __init__( + self, + *, + content: list["_models.RealtimeResponseInputMessageAssistantContent"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Literal["completed", "incomplete"]] = 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.role = RealtimeResponseInputMessageType.ASSISTANT # type: ignore + self.type: Literal["message"] = "message" + + +class RealtimeResponseInputMessageAssistantContent( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeResponseInputMessageAssistantContent. + + :ivar type: Required. Default value is "output_text". + :vartype type: str + :ivar text: Required. + :vartype text: str + """ + + type: Literal["output_text"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"output_text\".""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + text: 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["output_text"] = "output_text" + + +class RealtimeResponseInputMessageDeveloper( + RealtimeResponseInputMessage, discriminator="developer" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input developer message. + + :ivar id: An optional client ID. The value ``root`` is reserved. + :vartype id: str + :ivar type: Required. Default value is "message". + :vartype type: str + :ivar status: Optional input status. Omission or null defaults to completed. Is either a + Literal["completed"] type or a Literal["incomplete"] type. + :vartype status: str or str + :ivar role: Required. DEVELOPER. + :vartype role: str or ~azure.ai.projects.models.DEVELOPER + :ivar content: Required. + :vartype content: list[~azure.ai.projects.models.RealtimeResponseInputText] + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional client ID. The value ``root`` is reserved.""" + type: Literal["message"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"message\".""" + status: Optional[Literal["completed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional input status. Omission or null defaults to completed. Is either a + Literal[\"completed\"] type or a Literal[\"incomplete\"] type.""" + role: Literal[RealtimeResponseInputMessageType.DEVELOPER] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DEVELOPER.""" + content: list["_models.RealtimeResponseInputText"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + + @overload + def __init__( + self, + *, + content: list["_models.RealtimeResponseInputText"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Literal["completed", "incomplete"]] = 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.role = RealtimeResponseInputMessageType.DEVELOPER # type: ignore + self.type: Literal["message"] = "message" + + +class RealtimeResponseInputMessageSystem( + RealtimeResponseInputMessage, discriminator="system" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input system message. + + :ivar id: An optional client ID. The value ``root`` is reserved. + :vartype id: str + :ivar type: Required. Default value is "message". + :vartype type: str + :ivar status: Optional input status. Omission or null defaults to completed. Is either a + Literal["completed"] type or a Literal["incomplete"] type. + :vartype status: str or str + :ivar role: Required. SYSTEM. + :vartype role: str or ~azure.ai.projects.models.SYSTEM + :ivar content: Required. + :vartype content: list[~azure.ai.projects.models.RealtimeResponseInputText] + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional client ID. The value ``root`` is reserved.""" + type: Literal["message"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"message\".""" + status: Optional[Literal["completed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional input status. Omission or null defaults to completed. Is either a + Literal[\"completed\"] type or a Literal[\"incomplete\"] type.""" + role: Literal[RealtimeResponseInputMessageType.SYSTEM] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. SYSTEM.""" + content: list["_models.RealtimeResponseInputText"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + + @overload + def __init__( + self, + *, + content: list["_models.RealtimeResponseInputText"], + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Literal["completed", "incomplete"]] = 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.role = RealtimeResponseInputMessageType.SYSTEM # type: ignore + self.type: Literal["message"] = "message" + + +class RealtimeResponseInputMessageUser( + RealtimeResponseInputMessage, discriminator="user" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input user message. + + :ivar id: An optional client ID. The value ``root`` is reserved. + :vartype id: str + :ivar type: Required. Default value is "message". + :vartype type: str + :ivar status: Optional input status. Omission or null defaults to completed. Is either a + Literal["completed"] type or a Literal["incomplete"] type. + :vartype status: str or str + :ivar role: Required. USER. + :vartype role: str or ~azure.ai.projects.models.USER + :ivar content: Required. + :vartype content: list[~azure.ai.projects.models.RealtimeResponseInputText or + ~azure.ai.projects.models.RealtimeResponseInputAudio or + ~azure.ai.projects.models.RealtimeResponseInputImage] + """ + + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional client ID. The value ``root`` is reserved.""" + type: Literal["message"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"message\".""" + status: Optional[Literal["completed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional input status. Omission or null defaults to completed. Is either a + Literal[\"completed\"] type or a Literal[\"incomplete\"] type.""" + role: Literal[RealtimeResponseInputMessageType.USER] = rest_discriminator(name="role", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. USER.""" + content: list[ + Union[ + "_models.RealtimeResponseInputText", + "_models.RealtimeResponseInputAudio", + "_models.RealtimeResponseInputImage", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + content: list[ + Union[ + "_models.RealtimeResponseInputText", + "_models.RealtimeResponseInputAudio", + "_models.RealtimeResponseInputImage", + ] + ], + id: Optional[str] = None, # pylint: disable=redefined-builtin + status: Optional[Literal["completed", "incomplete"]] = 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.role = RealtimeResponseInputMessageType.USER # type: ignore + self.type: Literal["message"] = "message" + + +class RealtimeResponseInputText(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Realtime response input text. + + :ivar type: Required. Default value is "input_text". + :vartype type: str + :ivar text: Required. + :vartype text: str + """ + + type: Literal["input_text"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"input_text\".""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + text: 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["input_text"] = "input_text" + + +class RealtimeResponseItemReference(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reference an existing item in this Realtime session as response.create input. Item references + are only accepted in the response input array, not as new conversation items. + + :ivar type: The type of this item. Always ``item_reference``. Required. Default value is + "item_reference". + :vartype type: str + :ivar id: The ID of an existing item in the same Realtime session. Required. + :vartype id: str + """ + + type: Literal["item_reference"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The type of this item. Always ``item_reference``. Required. Default value is + \"item_reference\".""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of an existing item in the same Realtime session. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["item_reference"] = "item_reference" + + +class RealtimeResponseStatusDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeResponseStatusDetails. + + :ivar type: Is one of the following types: Literal["completed"], Literal["cancelled"], + Literal["failed"], Literal["incomplete"] + :vartype type: str or str or str or str + :ivar reason: Is one of the following types: Literal["turn_detected"], + Literal["client_cancelled"], Literal["max_output_tokens"], Literal["content_filter"] + :vartype reason: str or str or str or str + :ivar error: + :vartype error: ~azure.ai.projects.models.RealtimeResponseStatusDetailsError + """ + + type: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is one of the following types: Literal[\"completed\"], Literal[\"cancelled\"], + Literal[\"failed\"], Literal[\"incomplete\"]""" + reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is one of the following types: Literal[\"turn_detected\"], Literal[\"client_cancelled\"], + Literal[\"max_output_tokens\"], Literal[\"content_filter\"]""" + error: Optional["_models.RealtimeResponseStatusDetailsError"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + + @overload + def __init__( + self, + *, + type: Optional[Literal["completed", "cancelled", "failed", "incomplete"]] = None, + reason: Optional[Literal["turn_detected", "client_cancelled", "max_output_tokens", "content_filter"]] = None, + error: Optional["_models.RealtimeResponseStatusDetailsError"] = 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 RealtimeResponseStatusDetailsError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeResponseStatusDetailsError. + + :ivar type: + :vartype type: str + :ivar code: + :vartype code: str + :ivar message: + :vartype message: str + """ + + type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + type: Optional[str] = None, + code: Optional[str] = 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 RealtimeResponseUsage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeResponseUsage. + + :ivar total_tokens: + :vartype total_tokens: int + :ivar input_tokens: + :vartype input_tokens: int + :ivar output_tokens: + :vartype output_tokens: int + :ivar input_token_details: + :vartype input_token_details: ~azure.ai.projects.models.RealtimeResponseUsageInputTokenDetails + :ivar output_token_details: + :vartype output_token_details: + ~azure.ai.projects.models.RealtimeResponseUsageOutputTokenDetails + """ + + total_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + output_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input_token_details: Optional["_models.RealtimeResponseUsageInputTokenDetails"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + output_token_details: Optional["_models.RealtimeResponseUsageOutputTokenDetails"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + + @overload + def __init__( + self, + *, + total_tokens: Optional[int] = None, + input_tokens: Optional[int] = None, + output_tokens: Optional[int] = None, + input_token_details: Optional["_models.RealtimeResponseUsageInputTokenDetails"] = None, + output_token_details: Optional["_models.RealtimeResponseUsageOutputTokenDetails"] = 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 RealtimeResponseUsageInputTokenDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeResponseUsageInputTokenDetails. + + :ivar cached_tokens: + :vartype cached_tokens: int + :ivar text_tokens: + :vartype text_tokens: int + :ivar image_tokens: + :vartype image_tokens: int + :ivar audio_tokens: + :vartype audio_tokens: int + :ivar cached_tokens_details: + :vartype cached_tokens_details: + ~azure.ai.projects.models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails + """ + + cached_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + image_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + cached_tokens_details: Optional["_models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + + @overload + def __init__( + self, + *, + cached_tokens: Optional[int] = None, + text_tokens: Optional[int] = None, + image_tokens: Optional[int] = None, + audio_tokens: Optional[int] = None, + cached_tokens_details: Optional["_models.RealtimeResponseUsageInputTokenDetailsCachedTokensDetails"] = 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 RealtimeResponseUsageInputTokenDetailsCachedTokensDetails( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeResponseUsageInputTokenDetailsCachedTokensDetails. + + :ivar text_tokens: + :vartype text_tokens: int + :ivar image_tokens: + :vartype image_tokens: int + :ivar audio_tokens: + :vartype audio_tokens: int + """ + + text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + image_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + text_tokens: Optional[int] = None, + image_tokens: Optional[int] = None, + audio_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 RealtimeResponseUsageOutputTokenDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeResponseUsageOutputTokenDetails. + + :ivar text_tokens: + :vartype text_tokens: int + :ivar audio_tokens: + :vartype audio_tokens: int + """ + + text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + text_tokens: Optional[int] = None, + audio_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 RealtimeServerEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A realtime server event. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + RealtimeServerEventConversationItemAdded, RealtimeServerEventConversationItemCreated, + RealtimeServerEventConversationItemDeleted, RealtimeServerEventConversationItemDone, + RealtimeServerEventConversationItemInputAudioTranscriptionCompleted, + RealtimeServerEventConversationItemInputAudioTranscriptionDelta, + RealtimeServerEventConversationItemInputAudioTranscriptionFailed, + RealtimeServerEventConversationItemInputAudioTranscriptionSegment, + RealtimeServerEventConversationItemRetrieved, RealtimeServerEventConversationItemTruncated, + RealtimeServerEventInputAudioBufferCleared, RealtimeServerEventInputAudioBufferCommitted, + RealtimeServerEventInputAudioBufferSpeechStarted, + RealtimeServerEventInputAudioBufferSpeechStopped, + RealtimeServerEventInputAudioBufferTimeoutTriggered, + VoiceAgentServerEventInputCollectionStatus, RealtimeServerEventMCPListToolsCompleted, + RealtimeServerEventMCPListToolsFailed, RealtimeServerEventMCPListToolsInProgress, + RealtimeServerEventOutputAudioBufferCleared, RealtimeServerEventRateLimitsUpdated, + VoiceAgentServerEventResponseAnimationBlendshapesDelta, + VoiceAgentServerEventResponseAnimationBlendshapesDone, + VoiceAgentServerEventResponseAnimationVisemeDelta, + VoiceAgentServerEventResponseAnimationVisemeDone, + VoiceAgentServerEventResponseAudioTimestampDelta, + VoiceAgentServerEventResponseAudioTimestampDone, RealtimeServerEventResponseContentPartAdded, + RealtimeServerEventResponseContentPartDone, RealtimeServerEventResponseCreated, + RealtimeServerEventResponseDone, RealtimeServerEventResponseFunctionCallArgumentsDelta, + RealtimeServerEventResponseFunctionCallArgumentsDone, + RealtimeServerEventResponseMCPCallCompleted, RealtimeServerEventResponseMCPCallFailed, + RealtimeServerEventResponseMCPCallInProgress, RealtimeServerEventResponseMCPCallArgumentsDelta, + RealtimeServerEventResponseMCPCallArgumentsDone, RealtimeServerEventResponseAudioDelta, + RealtimeServerEventResponseAudioDone, RealtimeServerEventResponseAudioTranscriptDelta, + RealtimeServerEventResponseAudioTranscriptDone, RealtimeServerEventResponseOutputItemAdded, + RealtimeServerEventResponseOutputItemDone, RealtimeServerEventResponseTextDelta, + RealtimeServerEventResponseTextDone, VoiceAgentServerEventSystemToolArgumentsDelta, + VoiceAgentServerEventSystemToolArgumentsDone, VoiceAgentServerEventResponseVideoDelta, + VoiceAgentServerEventRtcCallError, VoiceAgentServerEventRtcCallSdpCreated, + VoiceAgentServerEventSessionAvatarConnecting, VoiceAgentServerEventSessionAvatarSwitchToIdle, + VoiceAgentServerEventSessionAvatarSwitchToSpeaking, RealtimeServerEventSessionCreated, + VoiceAgentServerEventSessionHandoffAborted, VoiceAgentServerEventSessionHandoffCompleted, + VoiceAgentServerEventSessionHandoffStarted, VoiceAgentServerEventSessionSubagentAborted, + VoiceAgentServerEventSessionSubagentCompleted, VoiceAgentServerEventSessionSubagentStarted, + RealtimeServerEventSessionUpdated, VoiceAgentServerEventWarning + + :ivar type: Required. Known values are: "warning", "session.subagent.started", + "session.subagent.completed", "session.subagent.aborted", "session.avatar.connecting", + "session.avatar.switch_to_speaking", "session.avatar.switch_to_idle", "rtc.call.sdp.created", + "rtc.call.error", "response.audio_timestamp.delta", "response.audio_timestamp.done", + "response.animation_blendshapes.delta", "response.animation_blendshapes.done", + "response.animation_viseme.delta", "response.animation_viseme.done", "response.video.delta", + "response.system_tool_arguments.delta", "response.system_tool_arguments.done", + "input_collection.status", "session.handoff.started", "session.handoff.completed", + "session.handoff.aborted", "conversation.created", "conversation.item.created", + "conversation.item.deleted", "conversation.item.input_audio_transcription.completed", + "conversation.item.input_audio_transcription.delta", + "conversation.item.input_audio_transcription.failed", "conversation.item.retrieved", + "conversation.item.truncated", "error", "input_audio_buffer.cleared", + "input_audio_buffer.committed", "input_audio_buffer.dtmf_event_received", + "input_audio_buffer.speech_started", "input_audio_buffer.speech_stopped", + "rate_limits.updated", "response.output_audio.delta", "response.output_audio.done", + "response.output_audio_transcript.delta", "response.output_audio_transcript.done", + "response.content_part.added", "response.content_part.done", "response.created", + "response.done", "response.function_call_arguments.delta", + "response.function_call_arguments.done", "response.output_item.added", + "response.output_item.done", "response.output_text.delta", "response.output_text.done", + "session.created", "session.updated", "output_audio_buffer.started", + "output_audio_buffer.stopped", "output_audio_buffer.cleared", "conversation.item.added", + "conversation.item.done", "input_audio_buffer.timeout_triggered", + "conversation.item.input_audio_transcription.segment", "mcp_list_tools.in_progress", + "mcp_list_tools.completed", "mcp_list_tools.failed", "response.mcp_call_arguments.delta", + "response.mcp_call_arguments.done", "response.mcp_call.in_progress", + "response.mcp_call.completed", and "response.mcp_call.failed". + :vartype type: str or ~azure.ai.projects.models.RealtimeServerEventType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"warning\", \"session.subagent.started\", + \"session.subagent.completed\", \"session.subagent.aborted\", \"session.avatar.connecting\", + \"session.avatar.switch_to_speaking\", \"session.avatar.switch_to_idle\", + \"rtc.call.sdp.created\", \"rtc.call.error\", \"response.audio_timestamp.delta\", + \"response.audio_timestamp.done\", \"response.animation_blendshapes.delta\", + \"response.animation_blendshapes.done\", \"response.animation_viseme.delta\", + \"response.animation_viseme.done\", \"response.video.delta\", + \"response.system_tool_arguments.delta\", \"response.system_tool_arguments.done\", + \"input_collection.status\", \"session.handoff.started\", \"session.handoff.completed\", + \"session.handoff.aborted\", \"conversation.created\", \"conversation.item.created\", + \"conversation.item.deleted\", \"conversation.item.input_audio_transcription.completed\", + \"conversation.item.input_audio_transcription.delta\", + \"conversation.item.input_audio_transcription.failed\", \"conversation.item.retrieved\", + \"conversation.item.truncated\", \"error\", \"input_audio_buffer.cleared\", + \"input_audio_buffer.committed\", \"input_audio_buffer.dtmf_event_received\", + \"input_audio_buffer.speech_started\", \"input_audio_buffer.speech_stopped\", + \"rate_limits.updated\", \"response.output_audio.delta\", \"response.output_audio.done\", + \"response.output_audio_transcript.delta\", \"response.output_audio_transcript.done\", + \"response.content_part.added\", \"response.content_part.done\", \"response.created\", + \"response.done\", \"response.function_call_arguments.delta\", + \"response.function_call_arguments.done\", \"response.output_item.added\", + \"response.output_item.done\", \"response.output_text.delta\", \"response.output_text.done\", + \"session.created\", \"session.updated\", \"output_audio_buffer.started\", + \"output_audio_buffer.stopped\", \"output_audio_buffer.cleared\", \"conversation.item.added\", + \"conversation.item.done\", \"input_audio_buffer.timeout_triggered\", + \"conversation.item.input_audio_transcription.segment\", \"mcp_list_tools.in_progress\", + \"mcp_list_tools.completed\", \"mcp_list_tools.failed\", \"response.mcp_call_arguments.delta\", + \"response.mcp_call_arguments.done\", \"response.mcp_call.in_progress\", + \"response.mcp_call.completed\", and \"response.mcp_call.failed\".""" + + @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 RealtimeServerEventConversationItemAdded( + RealtimeServerEvent, discriminator="conversation.item.added" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Sent by the server when an Item is added to the default Conversation. This can happen in + several cases: + + * When the client sends a `conversation.item.create` event. + * When the input audio buffer is committed. In this case the item will be a user message containing the audio from + the buffer. + * When the model is generating a Response. In this case the `conversation.item.added` event will be sent when the + model starts generating a specific Item, and thus it will not yet have any content (and `status` will be + `in_progress`). The event will include the full content of the Item (except when model is generating a Response) + except for audio data, which can be retrieved separately with a `conversation.item.retrieve` event if necessary. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.added``. Required. + CONVERSATION_ITEM_ADDED. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_ADDED + :ivar previous_item_id: + :vartype previous_item_id: str + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_ADDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.added``. Required. CONVERSATION_ITEM_ADDED.""" + previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item: "_models.RealtimeConversationItem", + previous_item_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 = RealtimeServerEventType.CONVERSATION_ITEM_ADDED # type: ignore + + +class RealtimeServerEventConversationItemCreated( + RealtimeServerEvent, discriminator="conversation.item.created" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when a conversation item is created. There are several scenarios that produce this + event: + + * The server is generating a Response, which if successful will produce either one or two Items, which will be of + type `message` (role `assistant`) or type `function_call`. + * The input audio buffer has been committed, either by the client or the server (in `server_vad` mode). The server + will take the content of the input audio buffer and add it to a new user message Item. + * The client has sent a `conversation.item.create` event to add a new Item to the Conversation. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.created``. Required. + CONVERSATION_ITEM_CREATED. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_CREATED + :ivar previous_item_id: + :vartype previous_item_id: str + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.created``. Required. CONVERSATION_ITEM_CREATED.""" + previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item: "_models.RealtimeConversationItem", + previous_item_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 = RealtimeServerEventType.CONVERSATION_ITEM_CREATED # type: ignore + + +class RealtimeServerEventConversationItemDeleted( + RealtimeServerEvent, discriminator="conversation.item.deleted" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an item in the conversation is deleted by the client with a + ``conversation.item.delete`` event. This event is used to synchronize the server's + understanding of the conversation history with the client's view. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.deleted``. Required. + CONVERSATION_ITEM_DELETED. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_DELETED + :ivar item_id: The ID of the item that was deleted. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DELETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.deleted``. Required. CONVERSATION_ITEM_DELETED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item that was deleted. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_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 = RealtimeServerEventType.CONVERSATION_ITEM_DELETED # type: ignore + + +class RealtimeServerEventConversationItemDone( + RealtimeServerEvent, discriminator="conversation.item.done" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a conversation item is finalized. The event will include the full content of the + Item except for audio data, which can be retrieved separately with a + ``conversation.item.retrieve`` event if needed. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.done``. Required. + CONVERSATION_ITEM_DONE. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_DONE + :ivar previous_item_id: + :vartype previous_item_id: str + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.done``. Required. CONVERSATION_ITEM_DONE.""" + previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item: "_models.RealtimeConversationItem", + previous_item_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 = RealtimeServerEventType.CONVERSATION_ITEM_DONE # type: ignore + + +class RealtimeServerEventConversationItemInputAudioTranscriptionCompleted( + RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.completed" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """This event is the output of audio transcription for user audio written to the user audio + buffer. Transcription begins when the input audio buffer is committed by the client or server + (when VAD is enabled). Transcription runs asynchronously with Response creation, so this event + may come before or after the Response events. Realtime API models accept audio natively, and + thus input transcription is a separate process run on a separate ASR (Automatic Speech + Recognition) model. The transcript may diverge somewhat from the model's interpretation, and + should be treated as a rough guide. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.input_audio_transcription.completed``. + Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED. + :vartype type: str or + ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED + :ivar item_id: The ID of the item containing the audio that is being transcribed. Required. + :vartype item_id: str + :ivar content_index: The index of the content part containing the audio. Required. + :vartype content_index: int + :ivar transcript: The transcribed text. Required. + :vartype transcript: str + :ivar languages: The languages detected in the audio. Returned by ``gpt-transcribe``. An empty + array indicates that no language could be reliably detected. + :vartype languages: list[~azure.ai.projects.models.TranscriptionLanguage] + :ivar logprobs: + :vartype logprobs: list[~azure.ai.projects.models.LogProbProperties] + :ivar usage: Usage statistics for the transcription, this is billed according to the ASR + model's pricing rather than the realtime model's pricing. Required. Is either a + TranscriptTextUsageTokens type or a TranscriptTextUsageDuration type. + :vartype usage: ~azure.ai.projects.models.TranscriptTextUsageTokens or + ~azure.ai.projects.models.TranscriptTextUsageDuration + :ivar phrases: Phrase-level transcription timing and confidence details. + :vartype phrases: list[~azure.ai.projects.models.VoiceAgentTranscriptionPhrase] + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.input_audio_transcription.completed``. Required. + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item containing the audio that is being transcribed. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part containing the audio. Required.""" + transcript: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The transcribed text. Required.""" + languages: Optional[list["_models.TranscriptionLanguage"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The languages detected in the audio. Returned by ``gpt-transcribe``. An empty array indicates + that no language could be reliably detected.""" + logprobs: Optional[list["_models.LogProbProperties"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + usage: Union["_models.TranscriptTextUsageTokens", "_models.TranscriptTextUsageDuration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Usage statistics for the transcription, this is billed according to the ASR model's pricing + rather than the realtime model's pricing. Required. Is either a TranscriptTextUsageTokens type + or a TranscriptTextUsageDuration type.""" + phrases: Optional[list["_models.VoiceAgentTranscriptionPhrase"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Phrase-level transcription timing and confidence details.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + content_index: int, + transcript: str, + usage: Union["_models.TranscriptTextUsageTokens", "_models.TranscriptTextUsageDuration"], + languages: Optional[list["_models.TranscriptionLanguage"]] = None, + logprobs: Optional[list["_models.LogProbProperties"]] = None, + phrases: Optional[list["_models.VoiceAgentTranscriptionPhrase"]] = 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 = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_COMPLETED # type: ignore + + +class RealtimeServerEventConversationItemInputAudioTranscriptionDelta( + RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.delta" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the text value of an input audio transcription content part is updated with + incremental transcription results. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.input_audio_transcription.delta``. + Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA. + :vartype type: str or + ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA + :ivar item_id: The ID of the item containing the audio that is being transcribed. Required. + :vartype item_id: str + :ivar content_index: The index of the content part in the item's content array. + :vartype content_index: int + :ivar delta: The text delta. + :vartype delta: str + :ivar logprobs: + :vartype logprobs: list[~azure.ai.projects.models.LogProbProperties] + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.input_audio_transcription.delta``. Required. + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item containing the audio that is being transcribed. Required.""" + content_index: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array.""" + delta: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text delta.""" + logprobs: Optional[list["_models.LogProbProperties"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + content_index: Optional[int] = None, + delta: Optional[str] = None, + logprobs: Optional[list["_models.LogProbProperties"]] = 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 = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_DELTA # type: ignore + + +class RealtimeServerEventConversationItemInputAudioTranscriptionFailed( + RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.failed" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when input audio transcription is configured, and a transcription request for a user + message failed. These events are separate from other ``error`` events so that the client can + identify the related Item. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.input_audio_transcription.failed``. + Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED. + :vartype type: str or + ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED + :ivar item_id: The ID of the user message item. Required. + :vartype item_id: str + :ivar content_index: The index of the content part containing the audio. Required. + :vartype content_index: int + :ivar error: Details of the transcription error. Required. + :vartype error: + ~azure.ai.projects.models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.input_audio_transcription.failed``. Required. + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the user message item. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part containing the audio. Required.""" + error: "_models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Details of the transcription error. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + content_index: int, + error: "_models.RealtimeServerEventConversationItemInputAudioTranscriptionFailedError", + ) -> 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 = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_FAILED # type: ignore + + +class RealtimeServerEventConversationItemInputAudioTranscriptionFailedError( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeServerEventConversationItemInputAudioTranscriptionFailedError. + + :ivar type: + :vartype type: str + :ivar code: + :vartype code: str + :ivar message: + :vartype message: str + :ivar param: + :vartype param: str + """ + + type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + param: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + type: Optional[str] = None, + code: Optional[str] = None, + message: Optional[str] = None, + param: 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 RealtimeServerEventConversationItemInputAudioTranscriptionSegment( + RealtimeServerEvent, discriminator="conversation.item.input_audio_transcription.segment" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an input audio transcription segment is identified for an item. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.input_audio_transcription.segment``. + Required. CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT. + :vartype type: str or + ~azure.ai.projects.models.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT + :ivar item_id: The ID of the item containing the input audio content. Required. + :vartype item_id: str + :ivar content_index: The index of the input audio content part within the item. Required. + :vartype content_index: int + :ivar text: The text for this segment. Required. + :vartype text: str + :ivar id: The segment identifier. Required. + :vartype id: str + :ivar speaker: The detected speaker label for this segment. Required. + :vartype speaker: str + :ivar start: Start time of the segment in seconds. Required. + :vartype start: float + :ivar end: End time of the segment in seconds. Required. + :vartype end: float + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.input_audio_transcription.segment``. Required. + CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item containing the input audio content. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the input audio content part within the item. Required.""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text for this segment. Required.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The segment identifier. Required.""" + speaker: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The detected speaker label for this segment. Required.""" + start: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Start time of the segment in seconds. Required.""" + end: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """End time of the segment in seconds. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + content_index: int, + text: str, + id: str, # pylint: disable=redefined-builtin + speaker: str, + start: float, + end: 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) + self.type = RealtimeServerEventType.CONVERSATION_ITEM_INPUT_AUDIO_TRANSCRIPTION_SEGMENT # type: ignore + + +class RealtimeServerEventConversationItemRetrieved( + RealtimeServerEvent, discriminator="conversation.item.retrieved" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when a conversation item is retrieved with ``conversation.item.retrieve``. This is + provided as a way to fetch the server's representation of an item, for example to get access to + the post-processed audio data after noise cancellation and VAD. It includes the full content of + the Item, including audio data. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.retrieved``. Required. + CONVERSATION_ITEM_RETRIEVED. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_RETRIEVED + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_RETRIEVED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.retrieved``. Required. CONVERSATION_ITEM_RETRIEVED.""" + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item: "_models.RealtimeConversationItem", + ) -> 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 = RealtimeServerEventType.CONVERSATION_ITEM_RETRIEVED # type: ignore + + +class RealtimeServerEventConversationItemTruncated( + RealtimeServerEvent, discriminator="conversation.item.truncated" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an earlier assistant audio message item is truncated by the client with a + ``conversation.item.truncate`` event. This event is used to synchronize the server's + understanding of the audio with the client's playback. This action will truncate the audio and + remove the server-side text transcript to ensure there is no text in the context that hasn't + been heard by the user. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``conversation.item.truncated``. Required. + CONVERSATION_ITEM_TRUNCATED. + :vartype type: str or ~azure.ai.projects.models.CONVERSATION_ITEM_TRUNCATED + :ivar item_id: The ID of the assistant message item that was truncated. Required. + :vartype item_id: str + :ivar content_index: The index of the content part that was truncated. Required. + :vartype content_index: int + :ivar audio_end_ms: The duration up to which the audio was truncated, in milliseconds. + Required. + :vartype audio_end_ms: int + :ivar item: The assistant message after truncation, when the service returns the updated item. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.CONVERSATION_ITEM_TRUNCATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``conversation.item.truncated``. Required. CONVERSATION_ITEM_TRUNCATED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the assistant message item that was truncated. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part that was truncated. Required.""" + audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The duration up to which the audio was truncated, in milliseconds. Required.""" + item: Optional["_models.RealtimeConversationItem"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The assistant message after truncation, when the service returns the updated item.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + content_index: int, + audio_end_ms: int, + item: Optional["_models.RealtimeConversationItem"] = 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 = RealtimeServerEventType.CONVERSATION_ITEM_TRUNCATED # type: ignore + + +class RealtimeServerEventError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when an error occurs, which could be a client problem or a server problem. Most errors + are recoverable and the session will stay open, we recommend to implementers to monitor and log + error messages by default. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``error``. Required. Default value is "error". + :vartype type: str + :ivar error: Details of the error. Required. + :vartype error: ~azure.ai.projects.models.RealtimeServerEventErrorError + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal["error"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event type, must be ``error``. Required. Default value is \"error\".""" + error: "_models.RealtimeServerEventErrorError" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Details of the error. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + error: "_models.RealtimeServerEventErrorError", + ) -> 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["error"] = "error" + + +class RealtimeServerEventErrorError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """RealtimeServerEventErrorError. + + :ivar type: Required. + :vartype type: str + :ivar code: + :vartype code: str + :ivar message: Required. + :vartype message: str + :ivar param: + :vartype param: str + :ivar event_id: + :vartype event_id: str + """ + + type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + param: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + type: str, + message: str, + code: Optional[str] = None, + param: Optional[str] = None, + event_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 RealtimeServerEventInputAudioBufferCleared( + RealtimeServerEvent, discriminator="input_audio_buffer.cleared" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the input audio buffer is cleared by the client with a + ``input_audio_buffer.clear`` event. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.cleared``. Required. + INPUT_AUDIO_BUFFER_CLEARED. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_CLEARED + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_CLEARED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.cleared``. Required. INPUT_AUDIO_BUFFER_CLEARED.""" + + @overload + def __init__( + self, + *, + event_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 = RealtimeServerEventType.INPUT_AUDIO_BUFFER_CLEARED # type: ignore + + +class RealtimeServerEventInputAudioBufferCommitted( + RealtimeServerEvent, discriminator="input_audio_buffer.committed" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an input audio buffer is committed, either by the client or automatically in + server VAD mode. The ``item_id`` property is the ID of the user message item that will be + created, thus a ``conversation.item.created`` event will also be sent to the client. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.committed``. Required. + INPUT_AUDIO_BUFFER_COMMITTED. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_COMMITTED + :ivar previous_item_id: + :vartype previous_item_id: str + :ivar item_id: The ID of the user message item that will be created. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_COMMITTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.committed``. Required. + INPUT_AUDIO_BUFFER_COMMITTED.""" + previous_item_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the user message item that will be created. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_id: str, + previous_item_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 = RealtimeServerEventType.INPUT_AUDIO_BUFFER_COMMITTED # type: ignore + + +class RealtimeServerEventInputAudioBufferSpeechStarted( + RealtimeServerEvent, discriminator="input_audio_buffer.speech_started" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Sent by the server when in ``server_vad`` mode to indicate that speech has been detected in the + audio buffer. This can happen any time audio is added to the buffer (unless speech is already + detected). The client may want to use this event to interrupt audio playback or provide visual + feedback to the user. The client should expect to receive a + ``input_audio_buffer.speech_stopped`` event when speech stops. The ``item_id`` property is the + ID of the user message item that will be created when speech stops and will also be included in + the ``input_audio_buffer.speech_stopped`` event (unless the client manually commits the audio + buffer during VAD activation). + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.speech_started``. Required. + INPUT_AUDIO_BUFFER_SPEECH_STARTED. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_SPEECH_STARTED + :ivar audio_start_ms: Milliseconds from the start of all audio written to the buffer during the + session when speech was first detected. This will correspond to the beginning of audio sent to + the model, and thus includes the ``prefix_padding_ms`` configured in the Session. Required. + :vartype audio_start_ms: int + :ivar item_id: The ID of the user message item that will be created when speech stops. + Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.speech_started``. Required. + INPUT_AUDIO_BUFFER_SPEECH_STARTED.""" + audio_start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds from the start of all audio written to the buffer during the session when speech + was first detected. This will correspond to the beginning of audio sent to the model, and thus + includes the ``prefix_padding_ms`` configured in the Session. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the user message item that will be created when speech stops. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + audio_start_ms: int, + item_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 = RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED # type: ignore + + +class RealtimeServerEventInputAudioBufferSpeechStopped( + RealtimeServerEvent, discriminator="input_audio_buffer.speech_stopped" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned in ``server_vad`` mode when the server detects the end of speech in the audio buffer. + The server will also send an ``conversation.item.created`` event with the user message item + that is created from the audio buffer. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.speech_stopped``. Required. + INPUT_AUDIO_BUFFER_SPEECH_STOPPED. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_SPEECH_STOPPED + :ivar audio_end_ms: Milliseconds since the session started when speech stopped. This will + correspond to the end of audio sent to the model, and thus includes the + ``min_silence_duration_ms`` configured in the Session. Required. + :vartype audio_end_ms: int + :ivar item_id: The ID of the user message item that will be created. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STOPPED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.speech_stopped``. Required. + INPUT_AUDIO_BUFFER_SPEECH_STOPPED.""" + audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds since the session started when speech stopped. This will correspond to the end of + audio sent to the model, and thus includes the ``min_silence_duration_ms`` configured in the + Session. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the user message item that will be created. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + audio_end_ms: int, + item_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 = RealtimeServerEventType.INPUT_AUDIO_BUFFER_SPEECH_STOPPED # type: ignore + + +class RealtimeServerEventInputAudioBufferTimeoutTriggered( + RealtimeServerEvent, discriminator="input_audio_buffer.timeout_triggered" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the Server VAD timeout is triggered for the input audio buffer. This is + configured with ``idle_timeout_ms`` in the ``turn_detection`` settings of the session, and it + indicates that there hasn't been any speech detected for the configured duration. The + ``audio_start_ms`` and ``audio_end_ms`` fields indicate the segment of audio after the last + model response up to the triggering time, as an offset from the beginning of audio written to + the input audio buffer. This means it demarcates the segment of audio that was silent and the + difference between the start and end values will roughly match the configured timeout. The + empty audio will be committed to the conversation as an ``input_audio`` item (there will be a + ``input_audio_buffer.committed`` event) and a model response will be generated. There may be + speech that didn't trigger VAD but is still detected by the model, so the model may respond + with something relevant to the conversation or a prompt to continue speaking. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``input_audio_buffer.timeout_triggered``. Required. + INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED + :ivar audio_start_ms: Millisecond offset of audio written to the input audio buffer that was + after the playback time of the last model response. Required. + :vartype audio_start_ms: int + :ivar audio_end_ms: Millisecond offset of audio written to the input audio buffer at the time + the timeout was triggered. Required. + :vartype audio_end_ms: int + :ivar item_id: The ID of the item associated with this segment. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``input_audio_buffer.timeout_triggered``. Required. + INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED.""" + audio_start_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Millisecond offset of audio written to the input audio buffer that was after the playback time + of the last model response. Required.""" + audio_end_ms: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Millisecond offset of audio written to the input audio buffer at the time the timeout was + triggered. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item associated with this segment. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + audio_start_ms: int, + audio_end_ms: int, + item_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 = RealtimeServerEventType.INPUT_AUDIO_BUFFER_TIMEOUT_TRIGGERED # type: ignore + + +class RealtimeServerEventMCPListToolsCompleted( + RealtimeServerEvent, discriminator="mcp_list_tools.completed" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when listing MCP tools has completed for an item. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``mcp_list_tools.completed``. Required. + MCP_LIST_TOOLS_COMPLETED. + :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS_COMPLETED + :ivar item_id: The ID of the MCP list tools item. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``mcp_list_tools.completed``. Required. MCP_LIST_TOOLS_COMPLETED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP list tools item. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_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 = RealtimeServerEventType.MCP_LIST_TOOLS_COMPLETED # type: ignore + + +class RealtimeServerEventMCPListToolsFailed( + RealtimeServerEvent, discriminator="mcp_list_tools.failed" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when listing MCP tools has failed for an item. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``mcp_list_tools.failed``. Required. MCP_LIST_TOOLS_FAILED. + :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS_FAILED + :ivar item_id: The ID of the MCP list tools item. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``mcp_list_tools.failed``. Required. MCP_LIST_TOOLS_FAILED.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP list tools item. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_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 = RealtimeServerEventType.MCP_LIST_TOOLS_FAILED # type: ignore + + +class RealtimeServerEventMCPListToolsInProgress( + RealtimeServerEvent, discriminator="mcp_list_tools.in_progress" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when listing MCP tools is in progress for an item. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``mcp_list_tools.in_progress``. Required. + MCP_LIST_TOOLS_IN_PROGRESS. + :vartype type: str or ~azure.ai.projects.models.MCP_LIST_TOOLS_IN_PROGRESS + :ivar item_id: The ID of the MCP list tools item. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.MCP_LIST_TOOLS_IN_PROGRESS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``mcp_list_tools.in_progress``. Required. MCP_LIST_TOOLS_IN_PROGRESS.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP list tools item. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + item_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 = RealtimeServerEventType.MCP_LIST_TOOLS_IN_PROGRESS # type: ignore + + +class RealtimeServerEventOutputAudioBufferCleared( + RealtimeServerEvent, discriminator="output_audio_buffer.cleared" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """**WebRTC/SIP Only:** Emitted when the output audio buffer is cleared. This happens either in + VAD mode when the user has interrupted (``input_audio_buffer.speech_started``), or when the + client has emitted the ``output_audio_buffer.clear`` event to manually cut off the current + audio response. `Learn more + `_. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``output_audio_buffer.cleared``. Required. + OUTPUT_AUDIO_BUFFER_CLEARED. + :vartype type: str or ~azure.ai.projects.models.OUTPUT_AUDIO_BUFFER_CLEARED + :ivar response_id: The unique ID of the response that produced the audio. Required. + :vartype response_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.OUTPUT_AUDIO_BUFFER_CLEARED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``output_audio_buffer.cleared``. Required. OUTPUT_AUDIO_BUFFER_CLEARED.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the response that produced the audio. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_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 = RealtimeServerEventType.OUTPUT_AUDIO_BUFFER_CLEARED # type: ignore + + +class RealtimeServerEventRateLimitsUpdated( + RealtimeServerEvent, discriminator="rate_limits.updated" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Emitted at the beginning of a Response to indicate the updated rate limits. When a Response is + created some tokens will be "reserved" for the output tokens, the rate limits shown here + reflect that reservation, which is then adjusted accordingly once the Response is completed. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``rate_limits.updated``. Required. RATE_LIMITS_UPDATED. + :vartype type: str or ~azure.ai.projects.models.RATE_LIMITS_UPDATED + :ivar rate_limits: List of rate limit information. Required. + :vartype rate_limits: + list[~azure.ai.projects.models.RealtimeServerEventRateLimitsUpdatedRateLimits] + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RATE_LIMITS_UPDATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``rate_limits.updated``. Required. RATE_LIMITS_UPDATED.""" + rate_limits: list["_models.RealtimeServerEventRateLimitsUpdatedRateLimits"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """List of rate limit information. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + rate_limits: list["_models.RealtimeServerEventRateLimitsUpdatedRateLimits"], + ) -> 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 = RealtimeServerEventType.RATE_LIMITS_UPDATED # type: ignore + + +class RealtimeServerEventRateLimitsUpdatedRateLimits( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeServerEventRateLimitsUpdatedRateLimits. + + :ivar name: Is either a Literal["requests"] type or a Literal["tokens"] type. + :vartype name: str or str + :ivar limit: + :vartype limit: int + :ivar remaining: + :vartype remaining: int + :ivar reset_seconds: + :vartype reset_seconds: float + """ + + name: Optional[Literal["requests", "tokens"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is either a Literal[\"requests\"] type or a Literal[\"tokens\"] type.""" + limit: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + remaining: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + reset_seconds: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + name: Optional[Literal["requests", "tokens"]] = None, + limit: Optional[int] = None, + remaining: Optional[int] = None, + reset_seconds: 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 RealtimeServerEventResponseAudioDelta( + RealtimeServerEvent, discriminator="response.output_audio.delta" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when the model-generated audio is updated. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_audio.delta``. Required. + RESPONSE_OUTPUT_AUDIO_DELTA. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_DELTA + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar delta: Base64-encoded audio data delta. Required. + :vartype delta: bytes + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_audio.delta``. Required. RESPONSE_OUTPUT_AUDIO_DELTA.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + delta: bytes = rest_field(visibility=["read", "create", "update", "delete", "query"], format="base64") + """Base64-encoded audio data delta. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + delta: bytes, + ) -> 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 = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DELTA # type: ignore + + +class RealtimeServerEventResponseAudioDone( + RealtimeServerEvent, discriminator="response.output_audio.done" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when the model-generated audio is done. Also emitted when a Response is interrupted, + incomplete, or cancelled. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_audio.done``. Required. + RESPONSE_OUTPUT_AUDIO_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_DONE + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_audio.done``. Required. RESPONSE_OUTPUT_AUDIO_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: 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 = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_DONE # type: ignore + + +class RealtimeServerEventResponseAudioTranscriptDelta( + RealtimeServerEvent, discriminator="response.output_audio_transcript.delta" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the model-generated transcription of audio output is updated. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_audio_transcript.delta``. Required. + RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar delta: The transcript delta. Required. + :vartype delta: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_audio_transcript.delta``. Required. + RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The transcript delta. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + delta: 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 = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DELTA # type: ignore + + +class RealtimeServerEventResponseAudioTranscriptDone( + RealtimeServerEvent, discriminator="response.output_audio_transcript.done" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the model-generated transcription of audio output is done streaming. Also emitted + when a Response is interrupted, incomplete, or cancelled. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_audio_transcript.done``. Required. + RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar transcript: The final transcript of the audio. Required. + :vartype transcript: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_audio_transcript.done``. Required. + RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + transcript: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The final transcript of the audio. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + transcript: 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 = RealtimeServerEventType.RESPONSE_OUTPUT_AUDIO_TRANSCRIPT_DONE # type: ignore + + +class RealtimeServerEventResponseContentPartAdded( + RealtimeServerEvent, discriminator="response.content_part.added" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when a new content part is added to an assistant message item during response + generation. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.content_part.added``. Required. + RESPONSE_CONTENT_PART_ADDED. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_CONTENT_PART_ADDED + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item to which the content part was added. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar part: The content part that was added. Required. + :vartype part: ~azure.ai.projects.models.RealtimeServerEventResponseContentPartAddedPart + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_ADDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.content_part.added``. Required. RESPONSE_CONTENT_PART_ADDED.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item to which the content part was added. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + part: "_models.RealtimeServerEventResponseContentPartAddedPart" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The content part that was added. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + part: "_models.RealtimeServerEventResponseContentPartAddedPart", + ) -> 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 = RealtimeServerEventType.RESPONSE_CONTENT_PART_ADDED # type: ignore + + +class RealtimeServerEventResponseContentPartAddedPart( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeServerEventResponseContentPartAddedPart. + + :ivar type: Is either a Literal["audio"] type or a Literal["text"] type. + :vartype type: str or str + :ivar text: + :vartype text: str + :ivar audio: + :vartype audio: str + :ivar transcript: + :vartype transcript: str + """ + + type: Optional[Literal["audio", "text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Is either a Literal[\"audio\"] type or a Literal[\"text\"] type.""" + text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + type: Optional[Literal["audio", "text"]] = None, + text: Optional[str] = None, + audio: Optional[str] = None, + transcript: 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 RealtimeServerEventResponseContentPartDone( + RealtimeServerEvent, discriminator="response.content_part.done" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when a content part is done streaming in an assistant message item. Also emitted when + a Response is interrupted, incomplete, or cancelled. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.content_part.done``. Required. + RESPONSE_CONTENT_PART_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_CONTENT_PART_DONE + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar part: The content part that is done. Required. + :vartype part: ~azure.ai.projects.models.RealtimeServerEventResponseContentPartDonePart + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_CONTENT_PART_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.content_part.done``. Required. RESPONSE_CONTENT_PART_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + part: "_models.RealtimeServerEventResponseContentPartDonePart" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The content part that is done. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + part: "_models.RealtimeServerEventResponseContentPartDonePart", + ) -> 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 = RealtimeServerEventType.RESPONSE_CONTENT_PART_DONE # type: ignore + + +class RealtimeServerEventResponseContentPartDonePart( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """RealtimeServerEventResponseContentPartDonePart. + + :ivar type: Is either a Literal["audio"] type or a Literal["text"] type. + :vartype type: str or str + :ivar text: + :vartype text: str + :ivar audio: + :vartype audio: str + :ivar transcript: + :vartype transcript: str + :ivar format: The audio format, when this is an audio content part. + :vartype format: ~azure.ai.projects.models.RealtimeAudioFormats + """ + + type: Optional[Literal["audio", "text"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Is either a Literal[\"audio\"] type or a Literal[\"text\"] type.""" + text: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + transcript: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + format: Optional["_models.RealtimeAudioFormats"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The audio format, when this is an audio content part.""" + + @overload + def __init__( + self, + *, + type: Optional[Literal["audio", "text"]] = None, + text: Optional[str] = None, + audio: Optional[str] = None, + transcript: Optional[str] = None, + format: Optional["_models.RealtimeAudioFormats"] = 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 RealtimeServerEventResponseCreated( + RealtimeServerEvent, discriminator="response.created" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a new Response is created. The first event of response creation, where the + response is in an initial state of ``in_progress``. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.created``. Required. RESPONSE_CREATED. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_CREATED + :ivar response: Required. + :vartype response: ~azure.ai.projects.models.VoiceAgentRealtimeResponse + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.created``. Required. RESPONSE_CREATED.""" + response: "_models.VoiceAgentRealtimeResponse" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response: "_models.VoiceAgentRealtimeResponse", + ) -> 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 = RealtimeServerEventType.RESPONSE_CREATED # type: ignore + + +class RealtimeServerEventResponseDone( + RealtimeServerEvent, discriminator="response.done" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a Response is done streaming. Always emitted, no matter the final state. The + Response object included in the ``response.done`` event will include all output Items in the + Response but will omit the raw audio data. Clients should check the ``status`` field of the + Response to determine if it was successful (``completed``) or if there was another outcome: + ``cancelled``, ``failed``, or ``incomplete``. A response will contain all output items that + were generated during the response, excluding any audio content. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.done``. Required. RESPONSE_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_DONE + :ivar response: Required. + :vartype response: ~azure.ai.projects.models.VoiceAgentRealtimeResponse + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.done``. Required. RESPONSE_DONE.""" + response: "_models.VoiceAgentRealtimeResponse" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response: "_models.VoiceAgentRealtimeResponse", + ) -> 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 = RealtimeServerEventType.RESPONSE_DONE # type: ignore + + +class RealtimeServerEventResponseFunctionCallArgumentsDelta( + RealtimeServerEvent, discriminator="response.function_call_arguments.delta" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the model-generated function call arguments are updated. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.function_call_arguments.delta``. Required. + RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the function call item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar call_id: The ID of the function call. Required. + :vartype call_id: str + :ivar delta: The arguments delta as a JSON string. Required. + :vartype delta: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.function_call_arguments.delta``. Required. + RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the function call item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the function call. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The arguments delta as a JSON string. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + call_id: str, + delta: 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 = RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA # type: ignore + + +class RealtimeServerEventResponseFunctionCallArgumentsDone( + RealtimeServerEvent, discriminator="response.function_call_arguments.done" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when the model-generated function call arguments are done streaming. Also emitted when + a Response is interrupted, incomplete, or cancelled. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.function_call_arguments.done``. Required. + RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the function call item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar call_id: The ID of the function call. Required. + :vartype call_id: str + :ivar name: The name of the function that was called. Required. + :vartype name: str + :ivar arguments: The final arguments as a JSON string. Required. + :vartype arguments: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.function_call_arguments.done``. Required. + RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the function call item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the function call. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function that was called. Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The final arguments as a JSON string. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + call_id: str, + name: str, + arguments: 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 = RealtimeServerEventType.RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE # type: ignore + + +class RealtimeServerEventResponseMCPCallArgumentsDelta( + RealtimeServerEvent, discriminator="response.mcp_call_arguments.delta" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when MCP tool call arguments are updated during response generation. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.mcp_call_arguments.delta``. Required. + RESPONSE_MCP_CALL_ARGUMENTS_DELTA. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_ARGUMENTS_DELTA + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the MCP tool call item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar delta: The JSON-encoded arguments delta. Required. + :vartype delta: str + :ivar obfuscation: + :vartype obfuscation: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.mcp_call_arguments.delta``. Required. + RESPONSE_MCP_CALL_ARGUMENTS_DELTA.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP tool call item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The JSON-encoded arguments delta. Required.""" + obfuscation: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + delta: str, + obfuscation: 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 = RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DELTA # type: ignore + + +class RealtimeServerEventResponseMCPCallArgumentsDone( + RealtimeServerEvent, discriminator="response.mcp_call_arguments.done" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when MCP tool call arguments are finalized during response generation. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.mcp_call_arguments.done``. Required. + RESPONSE_MCP_CALL_ARGUMENTS_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_ARGUMENTS_DONE + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the MCP tool call item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar arguments: The final JSON-encoded arguments string. Required. + :vartype arguments: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.mcp_call_arguments.done``. Required. + RESPONSE_MCP_CALL_ARGUMENTS_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP tool call item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The final JSON-encoded arguments string. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + arguments: 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 = RealtimeServerEventType.RESPONSE_MCP_CALL_ARGUMENTS_DONE # type: ignore + + +class RealtimeServerEventResponseMCPCallCompleted( + RealtimeServerEvent, discriminator="response.mcp_call.completed" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an MCP tool call has completed successfully. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.mcp_call.completed``. Required. + RESPONSE_MCP_CALL_COMPLETED. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_COMPLETED + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar item_id: The ID of the MCP tool call item. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.mcp_call.completed``. Required. RESPONSE_MCP_CALL_COMPLETED.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP tool call item. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + output_index: int, + item_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 = RealtimeServerEventType.RESPONSE_MCP_CALL_COMPLETED # type: ignore + + +class RealtimeServerEventResponseMCPCallFailed( + RealtimeServerEvent, discriminator="response.mcp_call.failed" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when an MCP tool call has failed. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.mcp_call.failed``. Required. + RESPONSE_MCP_CALL_FAILED. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_FAILED + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar item_id: The ID of the MCP tool call item. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_FAILED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.mcp_call.failed``. Required. RESPONSE_MCP_CALL_FAILED.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP tool call item. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + output_index: int, + item_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 = RealtimeServerEventType.RESPONSE_MCP_CALL_FAILED # type: ignore + + +class RealtimeServerEventResponseMCPCallInProgress( + RealtimeServerEvent, discriminator="response.mcp_call.in_progress" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an MCP tool call has started and is in progress. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.mcp_call.in_progress``. Required. + RESPONSE_MCP_CALL_IN_PROGRESS. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_MCP_CALL_IN_PROGRESS + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar item_id: The ID of the MCP tool call item. Required. + :vartype item_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_MCP_CALL_IN_PROGRESS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.mcp_call.in_progress``. Required. + RESPONSE_MCP_CALL_IN_PROGRESS.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the MCP tool call item. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + output_index: int, + item_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 = RealtimeServerEventType.RESPONSE_MCP_CALL_IN_PROGRESS # type: ignore + + +class RealtimeServerEventResponseOutputItemAdded( + RealtimeServerEvent, discriminator="response.output_item.added" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when a new Item is created during Response generation. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_item.added``. Required. + RESPONSE_OUTPUT_ITEM_ADDED. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_ITEM_ADDED + :ivar response_id: The ID of the Response to which the item belongs. Required. + :vartype response_id: str + :ivar output_index: The index of the output item in the Response. Required. + :vartype output_index: int + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_ADDED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_item.added``. Required. RESPONSE_OUTPUT_ITEM_ADDED.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the Response to which the item belongs. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the Response. Required.""" + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + output_index: int, + item: "_models.RealtimeConversationItem", + ) -> 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 = RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_ADDED # type: ignore + + +class RealtimeServerEventResponseOutputItemDone( + RealtimeServerEvent, discriminator="response.output_item.done" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Returned when an Item is done streaming. Also emitted when a Response is interrupted, + incomplete, or cancelled. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_item.done``. Required. + RESPONSE_OUTPUT_ITEM_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_ITEM_DONE + :ivar response_id: The ID of the Response to which the item belongs. Required. + :vartype response_id: str + :ivar output_index: The index of the output item in the Response. Required. + :vartype output_index: int + :ivar item: Required. + :vartype item: ~azure.ai.projects.models.RealtimeConversationItem + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_item.done``. Required. RESPONSE_OUTPUT_ITEM_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the Response to which the item belongs. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the Response. Required.""" + item: "_models.RealtimeConversationItem" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + output_index: int, + item: "_models.RealtimeConversationItem", + ) -> 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 = RealtimeServerEventType.RESPONSE_OUTPUT_ITEM_DONE # type: ignore + + +class RealtimeServerEventResponseTextDelta( + RealtimeServerEvent, discriminator="response.output_text.delta" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when the text value of an "output_text" content part is updated. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_text.delta``. Required. + RESPONSE_OUTPUT_TEXT_DELTA. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_TEXT_DELTA + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar delta: The text delta. Required. + :vartype delta: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_text.delta``. Required. RESPONSE_OUTPUT_TEXT_DELTA.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text delta. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + delta: 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 = RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DELTA # type: ignore + + +class RealtimeServerEventResponseTextDone( + RealtimeServerEvent, discriminator="response.output_text.done" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when the text value of an "output_text" content part is done streaming. Also emitted + when a Response is interrupted, incomplete, or cancelled. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``response.output_text.done``. Required. + RESPONSE_OUTPUT_TEXT_DONE. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_OUTPUT_TEXT_DONE + :ivar response_id: The ID of the response. Required. + :vartype response_id: str + :ivar item_id: The ID of the item. Required. + :vartype item_id: str + :ivar output_index: The index of the output item in the response. Required. + :vartype output_index: int + :ivar content_index: The index of the content part in the item's content array. Required. + :vartype content_index: int + :ivar text: The final text content. Required. + :vartype text: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``response.output_text.done``. Required. RESPONSE_OUTPUT_TEXT_DONE.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the response. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the item. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the output item in the response. Required.""" + content_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The index of the content part in the item's content array. Required.""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The final text content. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + content_index: int, + text: 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 = RealtimeServerEventType.RESPONSE_OUTPUT_TEXT_DONE # type: ignore + + +class RealtimeServerEventSessionCreated( + RealtimeServerEvent, discriminator="session.created" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a Session is created. Emitted automatically when a new connection is established + as the first server event. This event will contain the default Session configuration. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``session.created``. Required. SESSION_CREATED. + :vartype type: str or ~azure.ai.projects.models.SESSION_CREATED + :ivar session: The session configuration. Required. Is one of the following types: + VoiceAgentSessionResponseConfig + :vartype session: ~azure.ai.projects.models.VoiceAgentSessionResponseConfig + :ivar conversation_id: The session-scoped conversation id. When present, responses attached to + the session conversation use the same value in ``response.created`` and ``response.done``. + :vartype conversation_id: str + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.SESSION_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``session.created``. Required. SESSION_CREATED.""" + session: "_unions.VoiceAgentSessionResponse" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The session configuration. Required. Is one of the following types: + VoiceAgentSessionResponseConfig""" + conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The session-scoped conversation id. When present, responses attached to the session + conversation use the same value in ``response.created`` and ``response.done``.""" + + @overload + def __init__( + self, + *, + event_id: str, + session: "_unions.VoiceAgentSessionResponse", + 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 = RealtimeServerEventType.SESSION_CREATED # type: ignore + + +class RealtimeServerEventSessionUpdated( + RealtimeServerEvent, discriminator="session.updated" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Returned when a session is updated with a ``session.update`` event, unless there is an error. + + :ivar event_id: The unique ID of the server event. Required. + :vartype event_id: str + :ivar type: The event type, must be ``session.updated``. Required. SESSION_UPDATED. + :vartype type: str or ~azure.ai.projects.models.SESSION_UPDATED + :ivar session: The session configuration. Required. Is one of the following types: + VoiceAgentSessionResponseConfig + :vartype session: ~azure.ai.projects.models.VoiceAgentSessionResponseConfig + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the server event. Required.""" + type: Literal[RealtimeServerEventType.SESSION_UPDATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type, must be ``session.updated``. Required. SESSION_UPDATED.""" + session: "_unions.VoiceAgentSessionResponse" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The session configuration. Required. Is one of the following types: + VoiceAgentSessionResponseConfig""" + + @overload + def __init__( + self, + *, + event_id: str, + session: "_unions.VoiceAgentSessionResponse", + ) -> 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 = RealtimeServerEventType.SESSION_UPDATED # type: ignore + + +class Reasoning(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reasoning. + + :ivar mode: Controls the reasoning execution mode for the request. When returned on a response, + this is the effective execution mode. Known values are: "standard" and "pro". + :vartype mode: str or ~azure.ai.projects.models.ReasoningModeEnum + :ivar effort: Known values are: "none", "minimal", "low", "medium", "high", "xhigh", and "max". + :vartype effort: str or ~azure.ai.projects.models.ReasoningEffort + :ivar summary: Is one of the following types: Literal["auto"], Literal["concise"], + Literal["detailed"] + :vartype summary: str or str or str + :ivar context: Is one of the following types: Literal["auto"], Literal["current_turn"], + Literal["all_turns"] + :vartype context: str or str or str + :ivar generate_summary: Is one of the following types: Literal["auto"], Literal["concise"], + Literal["detailed"] + :vartype generate_summary: str or str or str + """ + + mode: Optional[Union[str, "_models.ReasoningModeEnum"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Controls the reasoning execution mode for the request. When returned on a response, this is the + effective execution mode. Known values are: \"standard\" and \"pro\".""" + effort: Optional[Union[str, "_models.ReasoningEffort"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"none\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", and \"max\".""" + summary: Optional[Literal["auto", "concise", "detailed"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is one of the following types: Literal[\"auto\"], Literal[\"concise\"], Literal[\"detailed\"]""" + context: Optional[Literal["auto", "current_turn", "all_turns"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is one of the following types: Literal[\"auto\"], Literal[\"current_turn\"], + Literal[\"all_turns\"]""" + generate_summary: Optional[Literal["auto", "concise", "detailed"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Is one of the following types: Literal[\"auto\"], Literal[\"concise\"], Literal[\"detailed\"]""" + + @overload + def __init__( + self, + *, + mode: Optional[Union[str, "_models.ReasoningModeEnum"]] = None, + effort: Optional[Union[str, "_models.ReasoningEffort"]] = None, + summary: Optional[Literal["auto", "concise", "detailed"]] = None, + context: Optional[Literal["auto", "current_turn", "all_turns"]] = None, + generate_summary: Optional[Literal["auto", "concise", "detailed"]] = 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 RecurrenceTrigger( + Trigger, discriminator="Recurrence" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Recurrence based trigger. + + :ivar type: Type of the trigger. Required. Recurrence based trigger. + :vartype type: str or ~azure.ai.projects.models.RECURRENCE + :ivar start_time: Start time for the recurrence schedule in ISO 8601 format. + :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. Defaults to ``UTC``. + :vartype time_zone: str + :ivar interval: Interval for the recurrence schedule. Required. + :vartype interval: int + :ivar schedule: Recurrence schedule for the recurrence trigger. Required. + :vartype schedule: ~azure.ai.projects.models.RecurrenceSchedule + """ + + type: Literal[TriggerType.RECURRENCE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Type of the trigger. Required. Recurrence based trigger.""" + start_time: Optional[datetime.datetime] = rest_field( + name="startTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Start time for the recurrence schedule in ISO 8601 format.""" + end_time: Optional[datetime.datetime] = rest_field( + name="endTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """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. 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"]) + """Recurrence schedule for the recurrence trigger. Required.""" + + @overload + def __init__( + self, + *, + interval: int, + schedule: "_models.RecurrenceSchedule", + start_time: Optional[datetime.datetime] = None, + end_time: Optional[datetime.datetime] = None, + 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 = TriggerType.RECURRENCE # type: ignore + + +class RedTeam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Red team details. + + :ivar name: Identifier of the red team run. Required. + :vartype name: str + :ivar display_name: Name of the red-team run. + :vartype display_name: str + :ivar num_turns: Number of simulation rounds. + :vartype num_turns: int + :ivar attack_strategies: List of attack strategies or nested lists of attack strategies. + :vartype attack_strategies: list[str or ~azure.ai.projects.models.AttackStrategy] + :ivar simulation_only: Simulation-only or Simulation + Evaluation. If ``true`` the scan outputs + conversation not evaluation result. The service defaults to ``false`` if a value is not + specified by the caller. + :vartype simulation_only: bool + :ivar risk_categories: List of risk categories to generate attack objectives for. + :vartype risk_categories: list[str or ~azure.ai.projects.models.RiskCategory] + :ivar application_scenario: Application scenario for the red team operation, to generate + scenario specific attacks. + :vartype application_scenario: str + :ivar tags: Red team's tags. Unlike properties, tags are fully mutable. + :vartype tags: dict[str, str] + :ivar properties: Red team's properties. Unlike tags, properties are add-only. Once added, a + property cannot be removed. + :vartype properties: dict[str, str] + :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.RedTeamTargetConfig + """ + + name: str = rest_field(name="id", visibility=["read"]) + """Identifier of the red team run. Required.""" + display_name: Optional[str] = rest_field( + name="displayName", visibility=["read", "create", "update", "delete", "query"] + ) + """Name of the red-team run.""" + num_turns: Optional[int] = rest_field(name="numTurns", visibility=["read", "create", "update", "delete", "query"]) + """Number of simulation rounds.""" + attack_strategies: Optional[list[Union[str, "_models.AttackStrategy"]]] = rest_field( + name="attackStrategies", visibility=["read", "create", "update", "delete", "query"] + ) + """List of attack strategies or nested lists of attack strategies.""" + simulation_only: Optional[bool] = rest_field( + name="simulationOnly", visibility=["read", "create", "update", "delete", "query"] + ) + """Simulation-only or Simulation + Evaluation. If ``true`` the scan outputs conversation not + evaluation result. The service defaults to ``false`` if a value is not specified by the caller.""" + risk_categories: Optional[list[Union[str, "_models.RiskCategory"]]] = rest_field( + name="riskCategories", visibility=["read", "create", "update", "delete", "query"] + ) + """List of risk categories to generate attack objectives for.""" + application_scenario: Optional[str] = rest_field( + name="applicationScenario", visibility=["read", "create", "update", "delete", "query"] + ) + """Application scenario for the red team operation, to generate scenario specific attacks.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Red team's tags. Unlike properties, tags are fully mutable.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Red team's properties. Unlike tags, properties are add-only. Once added, a property cannot be + removed.""" + status: Optional[str] = rest_field(visibility=["read"]) + """Status of the red-team. It is set by service and is read-only.""" + 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.RedTeamTargetConfig", + display_name: Optional[str] = None, + num_turns: Optional[int] = None, + attack_strategies: Optional[list[Union[str, "_models.AttackStrategy"]]] = None, + simulation_only: Optional[bool] = None, + risk_categories: Optional[list[Union[str, "_models.RiskCategory"]]] = None, + application_scenario: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + properties: 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 ReinforcementFineTuningDataGenerationJob( + DataGenerationJob, discriminator="reinforcement_finetuning_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reinforcement fine-tuning data generation job resource. This is a preview feature. + + :ivar id: Server-assigned unique identifier. Required. + :vartype id: str + :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 name: The display name of the data generation job. Required. + :vartype name: str + :ivar sources: The sources used for the data generation job. Required. + :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] + :ivar generation_configuration: The generation configuration for the data generation job. + Required. + :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration + :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds + since January 1, 1970). Required. + :vartype created_at: ~datetime.datetime + :ivar finished_at: The timestamp when the job was finished, represented in Unix time (seconds + since January 1, 1970). + :vartype finished_at: ~datetime.datetime + :ivar scenario: The scenario of the data generation job, which is Reinforcement Fine-tuning + preview for this model. Required. Reinforcement Fine-tuning preview scenario. + :vartype scenario: str or ~azure.ai.projects.models.REINFORCEMENT_FINETUNING_PREVIEW + :ivar output_configuration: Optional file output configuration for the generated reinforcement + fine-tuning data. + :vartype output_configuration: + ~azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobOutputConfiguration + """ + + scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The scenario of the data generation job, which is Reinforcement Fine-tuning preview for this + model. Required. Reinforcement Fine-tuning preview scenario.""" + output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional file output configuration for the generated reinforcement fine-tuning data.""" + + @overload + def __init__( + self, + *, + name: str, + sources: list["_models.DataGenerationJobSource"], + generation_configuration: "_models.DataGenerationJobConfiguration", + output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = 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.scenario = DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW # type: ignore + + +class ReinforcementFineTuningDataGenerationJobInputs( + DataGenerationJobInputs, discriminator="reinforcement_finetuning_preview" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Caller-supplied inputs for a reinforcement fine-tuning data generation job. This is a preview + feature. + + :ivar name: The display name of the data generation job. Required. + :vartype name: str + :ivar sources: The sources used for the data generation job. Required. + :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] + :ivar generation_configuration: The generation configuration for the data generation job. + Required. + :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration + :ivar scenario: The scenario of the data generation job, which is Reinforcement Fine-tuning + preview for this model. Required. Reinforcement Fine-tuning preview scenario. + :vartype scenario: str or ~azure.ai.projects.models.REINFORCEMENT_FINETUNING_PREVIEW + :ivar output_configuration: Optional file output configuration for the generated reinforcement + fine-tuning data. + :vartype output_configuration: + ~azure.ai.projects.models.ReinforcementFineTuningDataGenerationJobOutputConfiguration + """ + + scenario: Literal[DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The scenario of the data generation job, which is Reinforcement Fine-tuning preview for this + model. Required. Reinforcement Fine-tuning preview scenario.""" + output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional file output configuration for the generated reinforcement fine-tuning data.""" + + @overload + def __init__( + self, + *, + name: str, + sources: list["_models.DataGenerationJobSource"], + generation_configuration: "_models.DataGenerationJobConfiguration", + output_configuration: Optional["_models.ReinforcementFineTuningDataGenerationJobOutputConfiguration"] = 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.scenario = DataGenerationJobScenario.REINFORCEMENT_FINETUNING_PREVIEW # type: ignore + + +class ReinforcementFineTuningDataGenerationJobOutputConfiguration( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """File output configuration for a reinforcement fine-tuning data generation job. This is a + preview feature. + + :ivar name: Filename to assign to the generated fine-tuning file. Required. + :vartype name: str + :ivar write_mode: Controls how file outputs are written. If omitted, defaults to ``overwrite`` + and writes only the newly generated fine-tuning file content. Known values are: "overwrite" and + "merge". + :vartype write_mode: str or ~azure.ai.projects.models.DataGenerationJobOutputWriteMode + :ivar merge_file_id: File ID to merge into when ``write_mode`` is ``merge``. + :vartype merge_file_id: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Filename to assign to the generated fine-tuning file. Required.""" + write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Controls how file outputs are written. If omitted, defaults to ``overwrite`` and writes only + the newly generated fine-tuning file content. Known values are: \"overwrite\" and \"merge\".""" + merge_file_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """File ID to merge into when ``write_mode`` is ``merge``.""" + + @overload + def __init__( + self, + *, + name: str, + write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = None, + merge_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 ReminderPreviewToolboxTool( + ToolboxTool, discriminator="reminder_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A reminder tool stored in a toolbox. + + :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 type: Required. REMINDER_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.REMINDER_PREVIEW + """ + + type: Literal[ToolboxToolType.REMINDER_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. REMINDER_PREVIEW.""" + + @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 = ToolboxToolType.REMINDER_PREVIEW # type: ignore + + +class ResponsesProtocolConfiguration(_Model): + """Configuration specific to the responses protocol.""" + + +class ResponseUsageInputTokensDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """ResponseUsageInputTokensDetails. + + :ivar cached_tokens: Required. + :vartype cached_tokens: int + :ivar cache_write_tokens: Required. + :vartype cache_write_tokens: int + """ + + cached_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + cache_write_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + cached_tokens: int, + cache_write_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 ResponseUsageOutputTokensDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """ResponseUsageOutputTokensDetails. + + :ivar reasoning_tokens: Required. + :vartype reasoning_tokens: int + """ + + reasoning_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + reasoning_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 ResponseUsageResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """ResponseUsageResource. + + :ivar input_tokens: Required. + :vartype input_tokens: int + :ivar input_tokens_details: Required. + :vartype input_tokens_details: ~azure.ai.projects.models.InputTokensDetailsResource + :ivar output_tokens: Required. + :vartype output_tokens: int + :ivar output_tokens_details: Required. + :vartype output_tokens_details: ~azure.ai.projects.models.OutputTokensDetailsResource + :ivar total_tokens: Required. + :vartype total_tokens: int + """ + + input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + input_tokens_details: "_models.InputTokensDetailsResource" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + output_tokens_details: "_models.OutputTokensDetailsResource" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + input_tokens: int, + input_tokens_details: "_models.InputTokensDetailsResource", + output_tokens: int, + output_tokens_details: "_models.OutputTokensDetailsResource", + 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 Routine(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A routine definition returned by the service. + + :ivar name: The routine name. + :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. + :vartype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] + :ivar action: The action executed when the routine fires. + :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: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The routine name.""" + 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: Optional[dict[str, "_models.RoutineTrigger"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The triggers configured for the routine.""" + action: Optional["_models.RoutineAction"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The action executed when the routine fires.""" + 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, + *, + enabled: bool, + name: Optional[str] = None, + description: Optional[str] = None, + triggers: Optional[dict[str, "_models.RoutineTrigger"]] = None, + action: Optional["_models.RoutineAction"] = 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 RoutineAuthorization(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Optional authorization configuration for a routine dispatch. + + :ivar identity: The identity used when dispatching the routine. Defaults to agent when omitted; + set to creator only when the customer opts in to creator identity dispatch. Known values are: + "agent" and "creator". + :vartype identity: str or ~azure.ai.projects.models.RoutineDispatchIdentity + """ + + identity: Optional[Union[str, "_models.RoutineDispatchIdentity"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The identity used when dispatching the routine. Defaults to agent when omitted; set to creator + only when the customer opts in to creator identity dispatch. Known values are: \"agent\" and + \"creator\".""" + + @overload + def __init__( + self, + *, + identity: Optional[Union[str, "_models.RoutineDispatchIdentity"]] = 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): # pylint: disable=docstring-keyword-should-match-keyword-only + """A single routine run returned from the run history API. + + :ivar id: The unique run identifier for the routine attempt. Required. + :vartype id: str + :ivar status: The run status. Is one of the following types: str + :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. Known values are: + "custom", "github_issue", "schedule", and "timer". + :vartype trigger_type: str or ~azure.ai.projects.models.RoutineTriggerType + :ivar trigger_name: The configured trigger name that produced the routine attempt. + :vartype trigger_name: str + :ivar trigger_event_payload: The event payload captured from the event that triggered the + routine attempt, when available. + :vartype trigger_event_payload: dict[str, any] + :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 agent_id: The project-scoped agent identifier recorded for the routine attempt. + :vartype agent_id: str + :ivar agent_endpoint_id: The legacy endpoint-scoped agent identifier recorded for the routine + attempt. + :vartype agent_endpoint_id: str + :ivar conversation_id: The conversation identifier used by a responses API dispatch. + :vartype conversation_id: str + :ivar session_id: The hosted-agent session identifier used by an invocations API dispatch. + :vartype session_id: str + :ivar triggered_at: The logical trigger time recorded for the routine attempt. + :vartype triggered_at: ~datetime.datetime + :ivar scheduled_fire_at: The scheduled fire time recorded for timer and schedule deliveries. + :vartype scheduled_fire_at: ~datetime.datetime + :ivar started_at: The time when the underlying run started. + :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_status_code: The downstream error status code captured for a failed attempt, when + available. + :vartype error_status_code: int + :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 + """ + + id: str = rest_field(visibility=["read"]) + """The unique run identifier for the routine attempt. Required.""" + status: Optional["_unions.RoutineRunStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The run status. Is one of the following types: str""" + 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: Optional[Union[str, "_models.RoutineTriggerType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The trigger type that produced the routine attempt. Known values are: \"custom\", + \"github_issue\", \"schedule\", and \"timer\".""" + trigger_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The configured trigger name that produced the routine attempt.""" + trigger_event_payload: Optional[dict[str, Any]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The event payload captured from the event that triggered the routine attempt, when available.""" + 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\".""" + agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The project-scoped agent identifier recorded for the routine attempt.""" + agent_endpoint_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The legacy endpoint-scoped agent identifier recorded for the routine attempt.""" + conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The conversation identifier used by a responses API dispatch.""" + session_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The hosted-agent session identifier used by an invocations API dispatch.""" + 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.""" + scheduled_fire_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The scheduled fire time recorded for timer and schedule deliveries.""" + started_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The time when the underlying run started.""" + 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_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The downstream error status code captured for a failed 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.""" + + @overload + def __init__( + self, + *, + status: Optional["_unions.RoutineRunStatus"] = None, + phase: Optional[Union[str, "_models.RoutineRunPhase"]] = None, + trigger_type: Optional[Union[str, "_models.RoutineTriggerType"]] = None, + trigger_name: Optional[str] = None, + trigger_event_payload: Optional[dict[str, Any]] = None, + attempt_source: Optional[Union[str, "_models.RoutineAttemptSource"]] = None, + action_type: Optional[Union[str, "_models.RoutineActionType"]] = None, + agent_id: Optional[str] = None, + agent_endpoint_id: Optional[str] = None, + conversation_id: Optional[str] = None, + session_id: Optional[str] = None, + triggered_at: Optional[datetime.datetime] = None, + scheduled_fire_at: Optional[datetime.datetime] = None, + started_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_status_code: Optional[int] = None, + error_type: Optional[str] = None, + error_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 RubricBasedEvaluatorDefinition( + EvaluatorDefinition, discriminator="rubric" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """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 RubricGenerationInputQualityWarning(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A non-fatal advisory produced during rubric evaluator generation when resolved inputs are + technically valid but likely too weak to produce a high-quality rubric. Read-only; + service-generated. Persisted with the terminal EvaluatorGenerationJob. + + :ivar code: Stable searchable machine-readable warning code. Required. Known values are: + "empty_prompt", "short_prompt", "empty_agent_instructions", "short_agent_instructions", + "empty_dataset_content", "short_dataset_content", "low_trace_count", and + "insufficient_total_input". + :vartype code: str or ~azure.ai.projects.models.RubricGenerationInputQualityWarningCode + :ivar severity: Advisory severity. Initial values: ``warning``. Required. "warning" + :vartype severity: str or ~azure.ai.projects.models.RubricGenerationInputQualityWarningSeverity + :ivar message: Human-readable message suitable for direct SDK/CLI/UI display. Must not include + raw prompt, instruction, dataset, or trace text. Required. + :vartype message: str + :ivar source: Which source category the warning applies to. ``aggregate`` is used only for + cross-source warnings. Required. Known values are: "prompt", "agent", "dataset", and + "aggregate". + :vartype source: str or ~azure.ai.projects.models.RubricGenerationInputQualityWarningSource + :ivar source_index: Zero-based index into ``EvaluatorGenerationJob.sources`` when the warning + applies to a specific source. Omitted for aggregate warnings and for warnings not tied to one + source. + :vartype source_index: int + """ + + code: Union[str, "_models.RubricGenerationInputQualityWarningCode"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Stable searchable machine-readable warning code. Required. Known values are: \"empty_prompt\", + \"short_prompt\", \"empty_agent_instructions\", \"short_agent_instructions\", + \"empty_dataset_content\", \"short_dataset_content\", \"low_trace_count\", and + \"insufficient_total_input\".""" + severity: Union[str, "_models.RubricGenerationInputQualityWarningSeverity"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Advisory severity. Initial values: ``warning``. Required. \"warning\"""" + message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Human-readable message suitable for direct SDK/CLI/UI display. Must not include raw prompt, + instruction, dataset, or trace text. Required.""" + source: Union[str, "_models.RubricGenerationInputQualityWarningSource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Which source category the warning applies to. ``aggregate`` is used only for cross-source + warnings. Required. Known values are: \"prompt\", \"agent\", \"dataset\", and \"aggregate\".""" + source_index: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Zero-based index into ``EvaluatorGenerationJob.sources`` when the warning applies to a specific + source. Omitted for aggregate warnings and for warnings not tied to one source.""" + + @overload + def __init__( + self, + *, + code: Union[str, "_models.RubricGenerationInputQualityWarningCode"], + severity: Union[str, "_models.RubricGenerationInputQualityWarningSeverity"], + message: str, + source: Union[str, "_models.RubricGenerationInputQualityWarningSource"], + source_index: 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 SASCredentials(BaseCredentials, discriminator="SAS"): + """Shared Access Signature (SAS) credential definition. + + :ivar type: The credential type. Required. Shared Access Signature (SAS) credential. + :vartype type: str or ~azure.ai.projects.models.SAS + :ivar sas_token: SAS token. + :vartype sas_token: str + """ + + type: Literal[CredentialType.SAS] = rest_discriminator(name="type", visibility=["read"]) # type: ignore + """The credential type. Required. Shared Access Signature (SAS) credential.""" + sas_token: Optional[str] = rest_field(name="SAS", visibility=["read"]) + """SAS token.""" + + @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 = CredentialType.SAS # type: ignore + + +class Schedule(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Schedule model. + + :ivar schedule_id: Identifier of the schedule. Required. + :vartype schedule_id: str + :ivar display_name: Name of the schedule. + :vartype display_name: str + :ivar description: Description of the schedule. + :vartype description: str + :ivar enabled: Enabled status of the schedule. Required. + :vartype enabled: bool + :ivar provisioning_status: Provisioning status of the schedule. Known values are: "Creating", + "Updating", "Deleting", "Succeeded", and "Failed". + :vartype provisioning_status: str or ~azure.ai.projects.models.ScheduleProvisioningStatus + :ivar trigger: Trigger for the schedule. Required. + :vartype trigger: ~azure.ai.projects.models.Trigger + :ivar task: Task for the schedule. Required. + :vartype task: ~azure.ai.projects.models.ScheduleTask + :ivar tags: Schedule's tags. Unlike properties, tags are fully mutable. + :vartype tags: dict[str, str] + :ivar properties: Schedule's properties. Unlike tags, properties are add-only. Once added, a + property cannot be removed. + :vartype properties: dict[str, str] + :ivar system_data: System metadata for the resource. Required. + :vartype system_data: dict[str, str] + """ + + schedule_id: str = rest_field(name="id", visibility=["read"]) + """Identifier of the schedule. Required.""" + display_name: Optional[str] = rest_field( + name="displayName", visibility=["read", "create", "update", "delete", "query"] + ) + """Name of the schedule.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description of the schedule.""" + enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Enabled status of the schedule. Required.""" + provisioning_status: Optional[Union[str, "_models.ScheduleProvisioningStatus"]] = rest_field( + name="provisioningStatus", visibility=["read"] + ) + """Provisioning status of the schedule. Known values are: \"Creating\", \"Updating\", + \"Deleting\", \"Succeeded\", and \"Failed\".""" + trigger: "_models.Trigger" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Trigger for the schedule. Required.""" + task: "_models.ScheduleTask" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Task for the schedule. Required.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Schedule's tags. Unlike properties, tags are fully mutable.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Schedule's properties. Unlike tags, properties are add-only. Once added, a property cannot be + removed.""" + system_data: dict[str, str] = rest_field(name="systemData", visibility=["read"]) + """System metadata for the resource. Required.""" + + @overload + def __init__( + self, + *, + enabled: bool, + trigger: "_models.Trigger", + task: "_models.ScheduleTask", + display_name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + properties: 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 ScheduleRoutineTrigger( + RoutineTrigger, discriminator="schedule" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """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): # pylint: disable=docstring-keyword-should-match-keyword-only + """Schedule run model. + + :ivar run_id: Identifier of the schedule run. Required. + :vartype run_id: str + :ivar schedule_id: Identifier of the schedule. Required. + :vartype schedule_id: str + :ivar success: Trigger success status of the schedule run. Required. + :vartype success: bool + :ivar trigger_time: Trigger time of the schedule run. + :vartype trigger_time: ~datetime.datetime + :ivar error: Error information for the schedule run. + :vartype error: str + :ivar properties: Properties of the schedule run. Required. + :vartype properties: dict[str, str] + """ + + run_id: str = rest_field(name="id", visibility=["read"]) + """Identifier of the schedule run. Required.""" + schedule_id: str = rest_field(name="scheduleId", visibility=["read", "create", "update", "delete", "query"]) + """Identifier of the schedule. Required.""" + success: bool = rest_field(visibility=["read"]) + """Trigger success status of the schedule run. Required.""" + trigger_time: Optional[datetime.datetime] = rest_field( + name="triggerTime", visibility=["read", "create", "update", "delete", "query"], format="rfc3339" + ) + """Trigger time of the schedule run.""" + error: Optional[str] = rest_field(visibility=["read"]) + """Error information for the schedule run.""" + properties: dict[str, str] = rest_field(visibility=["read"]) + """Properties of the schedule run. Required.""" + + @overload + def __init__( + self, + *, + schedule_id: str, + trigger_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) + + +class ScoreProbabilityResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """ScoreProbabilityResource. + + :ivar value: Required. + :vartype value: int + :ivar label: Required. + :vartype label: str + :ivar probability: Required. + :vartype probability: float + """ + + value: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + probability: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + value: int, + label: str, + probability: 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 SessionConfiguration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Session defaults applied to sessions created for a hosted agent version. + + :ivar idle_timeout_seconds: The idle duration, in seconds, before a session's sandbox is + suspended. When omitted, the server defaults to 900 seconds. Must be between 120 and 14400 + seconds (4 hours). + :vartype idle_timeout_seconds: ~datetime.timedelta + """ + + idle_timeout_seconds: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + ) + """The idle duration, in seconds, before a session's sandbox is suspended. When omitted, the + server defaults to 900 seconds. Must be between 120 and 14400 seconds (4 hours).""" + + @overload + def __init__( + self, + *, + idle_timeout_seconds: Optional[datetime.timedelta] = 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 SessionDirectoryEntry(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A single entry in a directory listing. + + :ivar name: The name of the file or directory. Required. + :vartype name: str + :ivar size: The size in bytes (0 for directories). Required. + :vartype size: int + :ivar is_directory: Whether this entry is a directory. Required. + :vartype is_directory: bool + :ivar modified_time: The Unix timestamp (in seconds) when the file was last modified. Required. + :vartype modified_time: ~datetime.datetime + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the file or directory. Required.""" + size: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The size in bytes (0 for directories). Required.""" + is_directory: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether this entry is a directory. Required.""" + modified_time: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) when the file was last modified. Required.""" + + @overload + def __init__( + self, + *, + name: str, + size: int, + is_directory: bool, + modified_time: datetime.datetime, + ) -> 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 SessionFileWriteResult(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Response from uploading a file to a session sandbox. + + :ivar path: The path where the file was written, relative to the session home directory. + Required. + :vartype path: str + :ivar bytes_written: Number of bytes written. Required. + :vartype bytes_written: int + """ + + path: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The path where the file was written, relative to the session home directory. Required.""" + bytes_written: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of bytes written. Required.""" + + @overload + def __init__( + self, + *, + path: str, + bytes_written: 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 SessionLogEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A single Server-Sent Event frame emitted by the hosted agent session log stream. + + Each frame contains an ``event`` field identifying the event type and a ``data`` + field carrying the payload as plain text. Although the current ``data`` payload + is JSON-formatted, its schema is not contractual — additional keys may appear + and the format may change over time. Clients should treat ``data`` as an + opaque string and optionally attempt JSON parsing. + + New event types may be added in the future. Clients should gracefully + ignore unrecognized event types. + + Wire format: + + .. code-block:: + + event: log + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting server on port 18080"} + + event: log + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} + + :ivar event: The SSE event type. Currently ``log``, but additional event types may be added in + the future. Clients should ignore unrecognized event types. Required. "log" + :vartype event: str or ~azure.ai.projects.models.SessionLogEventType + :ivar data: The event payload as plain text. Currently JSON-formatted but the schema is not + contractual and may change. Required. + :vartype data: str + """ + + event: Union[str, "_models.SessionLogEventType"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The SSE event type. Currently ``log``, but additional event types may be added in the future. + Clients should ignore unrecognized event types. Required. \"log\"""" + data: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The event payload as plain text. Currently JSON-formatted but the schema is not contractual and + may change. Required.""" + + @overload + def __init__( + self, + *, + event: Union[str, "_models.SessionLogEventType"], + 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) + + +class SharepointGroundingToolParameters(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The sharepoint grounding tool parameters. + + :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] + """ + + 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, + *, + 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 SharepointPreviewTool( + Tool, discriminator="sharepoint_grounding_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The input definition information for a sharepoint tool as used to configure an agent. + + :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 sharepoint_grounding_preview: The sharepoint grounding tool parameters. Required. + :vartype sharepoint_grounding_preview: + ~azure.ai.projects.models.SharepointGroundingToolParameters + """ + + 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.""" + sharepoint_grounding_preview: "_models.SharepointGroundingToolParameters" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The sharepoint grounding tool parameters. Required.""" + + @overload + def __init__( + self, + *, + sharepoint_grounding_preview: "_models.SharepointGroundingToolParameters", + ) -> 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.SHAREPOINT_GROUNDING_PREVIEW # type: ignore + + +class ShellToolboxTool( + ToolboxTool, discriminator="shell" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A shell tool stored in a toolbox. This model is additive to toolbox configuration and does not + modify the OpenAI tool contract or existing toolbox tool definitions. + + :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 type: The type of the tool. Always ``shell``. Required. SHELL. + :vartype type: str or ~azure.ai.projects.models.SHELL + :ivar allowed_callers: + :vartype allowed_callers: list[str or ~azure.ai.projects.models.CallableToolAllowedCaller] + :ivar environment: The environment in which shell commands are executed. Specify an + automatically provisioned container or an existing container. Required. + :vartype environment: ~azure.ai.projects.models.ToolboxShellEnvironment + """ + + type: Literal[ToolboxToolType.SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``shell``. Required. SHELL.""" + allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + environment: "_models.ToolboxShellEnvironment" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The environment in which shell commands are executed. Specify an automatically provisioned + container or an existing container. Required.""" + + @overload + def __init__( + self, + *, + environment: "_models.ToolboxShellEnvironment", + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + allowed_callers: Optional[list[Union[str, "_models.CallableToolAllowedCaller"]]] = 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 = ToolboxToolType.SHELL # type: ignore + + +class SimpleQnADataGenerationJobConfiguration( + DataGenerationJobConfiguration, discriminator="simple_qna" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The configuration for a data generation job with SimpleQnA type. + + :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 max_samples: Maximum number of samples to generate, up to service-defined limits. + Required. + :vartype max_samples: int + :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.""" + max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of samples to generate, up to service-defined limits. Required.""" + 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 SimulationSeedDataGenerationJobConfiguration( + DataGenerationJobConfiguration, discriminator="simulation_seed" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The configuration for a task generation data generation job. Use with multiturn evaluation + scenarios and with prompt, file, or agent sources. Generated dataset rows include fields such + as ``id``, ``category``, ``test_case_description``, and ``desired_num_turns``. + + :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 SimulationSeed for this model. Required. + Simulation seed for evaluation scenarios. + :vartype type: str or ~azure.ai.projects.models.SIMULATION_SEED + :ivar max_samples: Maximum number of samples to generate, up to service-defined limits. + Required. + :vartype max_samples: int + """ + + type: Literal[DataGenerationJobType.SIMULATION_SEED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The data generation job type, which is SimulationSeed for this model. Required. Simulation seed + for evaluation scenarios.""" + max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of samples to generate, up to service-defined limits. Required.""" + + @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.SIMULATION_SEED # type: ignore + + +class SipAddress(TelephonyAddress, discriminator="sip"): # pylint: disable=docstring-keyword-should-match-keyword-only + """SIP/SIPS transfer address, subject to provider validation. SIP outbound sources and recipients + use phone_number, not SIP URIs. + + :ivar type: The SIP address type. Required. A SIP or SIPS destination for transfer. + :vartype type: str or ~azure.ai.projects.models.SIP + :ivar value: The SIP or SIPS URI to call. Required. + :vartype value: str + """ + + type: Literal[TelephonyAddressType.SIP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The SIP address type. Required. A SIP or SIPS destination for transfer.""" + + @overload + def __init__( + self, + *, + value: 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 = TelephonyAddressType.SIP # type: ignore + + +class TelephonyBinding(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A telephony binding owned by a voice agent. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + SipTelephonyBinding, TeamsPhoneExtensibilityTelephonyBinding, TwilioTelephonyBinding + + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar provider: The telephony provider. Required. Known values are: + "teams_phone_extensibility", "twilio", and "sip". + :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated incoming address: an HTTPS webhook for + webhook-based providers or a SIP/SIPS ingress URI for SIP. Required. + :vartype incoming_call_url: str + """ + + __mapping__: dict[str, _Model] = {} + id: str = rest_field(visibility=["read"]) + """The service-generated binding identifier. Required.""" + provider: str = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) + """The telephony provider. Required. Known values are: \"teams_phone_extensibility\", \"twilio\", + and \"sip\".""" + connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Foundry connection name for the telephony provider. Required.""" + label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The optional display label for the binding.""" + incoming_call_url: str = rest_field(visibility=["read"]) + """The service-generated incoming address: an HTTPS webhook for webhook-based providers or a + SIP/SIPS ingress URI for SIP. Required.""" + + @overload + def __init__( + self, + *, + provider: str, + connection_name: str, + label: 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 SipTelephonyBinding( + TelephonyBinding, discriminator="sip" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Inbound binding using a same-project SipInbound connection for authentication/network + restrictions. Creation does not prove regional runtime readiness. + + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated incoming address: an HTTPS webhook for + webhook-based providers or a SIP/SIPS ingress URI for SIP. Required. + :vartype incoming_call_url: str + :ivar provider: The SIP provider. Required. Session Initiation Protocol. + :vartype provider: str or ~azure.ai.projects.models.SIP + :ivar phone_number: Optional display metadata, not a routing key or E.164-constrained + destination. + :vartype phone_number: str + :ivar allowed_calling_numbers: Exact E.164 caller numbers or restricted anchored patterns, + validated by the service. Omit or use [] for no restriction. + :vartype allowed_calling_numbers: list[str] + """ + + provider: Literal[TelephonyProvider.SIP] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The SIP provider. Required. Session Initiation Protocol.""" + phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional display metadata, not a routing key or E.164-constrained destination.""" + allowed_calling_numbers: Optional[list[str]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Exact E.164 caller numbers or restricted anchored patterns, validated by the service. Omit or + use [] for no restriction.""" + + @overload + def __init__( + self, + *, + connection_name: str, + label: Optional[str] = None, + phone_number: Optional[str] = None, + allowed_calling_numbers: 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) + self.provider = TelephonyProvider.SIP # type: ignore + + +class TelephonyBindingListItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A telephony binding returned in a list, including its entity tag. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + SipTelephonyBindingListItem, TeamsPhoneExtensibilityTelephonyBindingListItem, + TwilioTelephonyBindingListItem + + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar provider: The telephony provider. Required. Known values are: + "teams_phone_extensibility", "twilio", and "sip". + :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated HTTPS webhook or SIP/SIPS ingress URI to + configure with the telephony provider. Required. + :vartype incoming_call_url: str + :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this + binding. Required. + :vartype etag: str + """ + + __mapping__: dict[str, _Model] = {} + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The service-generated binding identifier. Required.""" + provider: str = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) + """The telephony provider. Required. Known values are: \"teams_phone_extensibility\", \"twilio\", + and \"sip\".""" + connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Foundry connection name for the telephony provider. Required.""" + label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The optional display label for the binding.""" + incoming_call_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The service-generated HTTPS webhook or SIP/SIPS ingress URI to configure with the telephony + provider. Required.""" + etag: str = rest_field(visibility=["read"]) + """The entity tag to send in the ``If-Match`` header when updating or deleting this binding. + Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + provider: str, + connection_name: str, + incoming_call_url: str, + label: 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 SipTelephonyBindingListItem( + TelephonyBindingListItem, discriminator="sip" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An inbound SIP binding returned in a list, including its current entity tag. + + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated HTTPS webhook or SIP/SIPS ingress URI to + configure with the telephony provider. Required. + :vartype incoming_call_url: str + :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this + binding. Required. + :vartype etag: str + :ivar provider: The SIP provider. Required. Session Initiation Protocol. + :vartype provider: str or ~azure.ai.projects.models.SIP + :ivar phone_number: Optional display phone metadata, not a routing key. + :vartype phone_number: str + :ivar allowed_calling_numbers: Current exact E.164 caller numbers or restricted fully anchored + patterns. + :vartype allowed_calling_numbers: list[str] + """ + + provider: Literal[TelephonyProvider.SIP] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The SIP provider. Required. Session Initiation Protocol.""" + phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional display phone metadata, not a routing key.""" + allowed_calling_numbers: Optional[list[str]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Current exact E.164 caller numbers or restricted fully anchored patterns.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + connection_name: str, + incoming_call_url: str, + label: Optional[str] = None, + phone_number: Optional[str] = None, + allowed_calling_numbers: 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) + self.provider = TelephonyProvider.SIP # type: ignore + + +class SkillDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A skill resource. + + :ivar id: The unique identifier of the skill. Required. + :vartype id: str + :ivar name: The unique name of the skill. Required. + :vartype name: str + :ivar description: A human-readable description of the skill. Required. + :vartype description: str + :ivar created_at: The Unix timestamp (seconds) when the skill was created. Required. + :vartype created_at: ~datetime.datetime + :ivar default_version: The default version for the skill. Can be changed via updateSkill. + Required. + :vartype default_version: str + :ivar latest_version: The latest version for the skill. Required. + :vartype latest_version: str + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of the skill. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique name of the skill. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the skill. Required.""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (seconds) when the skill was created. Required.""" + default_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The default version for the skill. Can be changed via updateSkill. Required.""" + latest_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The latest version for the skill. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + name: str, + description: str, + created_at: datetime.datetime, + default_version: str, + latest_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 SkillInlineContent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Inline content for defining a simple skill without uploading files. Follows the agentskills.io + SKILL.md specification. + + :ivar description: A human-readable description of what the skill does and when to use it. + Required. + :vartype description: str + :ivar instructions: The skill instructions in markdown format. This is the body content of the + SKILL.md file. Required. + :vartype instructions: str + :ivar license: License name or reference to a bundled license file. + :vartype license: str + :ivar compatibility: Environment requirements or compatibility notes for the skill. + :vartype compatibility: str + :ivar metadata: Arbitrary key-value metadata for additional properties. + :vartype metadata: dict[str, str] + :ivar allowed_tools: List of pre-approved tools the skill may use. Experimental. + :vartype allowed_tools: list[str] + """ + + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of what the skill does and when to use it. Required.""" + instructions: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The skill instructions in markdown format. This is the body content of the SKILL.md file. + Required.""" + license: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """License name or reference to a bundled license file.""" + compatibility: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Environment requirements or compatibility notes for the skill.""" + metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Arbitrary key-value metadata for additional properties.""" + allowed_tools: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """List of pre-approved tools the skill may use. Experimental.""" + + @overload + def __init__( + self, + *, + description: str, + instructions: str, + license: Optional[str] = None, + compatibility: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + allowed_tools: 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 SkillReference(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A reference to a versioned Foundry skill. + + :ivar name: The name of the skill. Required. + :vartype name: str + :ivar version: The skill version. If omitted, the current default version is resolved and + pinned when the agent version is created. + :vartype version: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the skill. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The skill version. If omitted, the current default version is resolved and pinned when the + agent version is created.""" + + @overload + def __init__( + self, + *, + name: str, + version: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class SkillReferenceParam( + ContainerSkill, discriminator="skill_reference" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """SkillReferenceParam. + + :ivar type: References a skill created with the /v1/skills endpoint. Required. SKILL_REFERENCE. + :vartype type: str or ~azure.ai.projects.models.SKILL_REFERENCE + :ivar skill_id: The ID of the referenced skill. Required. + :vartype skill_id: str + :ivar version: Optional skill version. Use a positive integer or 'latest'. Omit for default. + :vartype version: str + """ + + type: Literal[ContainerSkillType.SKILL_REFERENCE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """References a skill created with the /v1/skills endpoint. Required. SKILL_REFERENCE.""" + skill_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the referenced skill. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional skill version. Use a positive integer or 'latest'. Omit for default.""" + + @overload + def __init__( + self, + *, + skill_id: str, + 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 = ContainerSkillType.SKILL_REFERENCE # type: ignore + + +class SkillVersion(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A specific version of a skill. + + :ivar id: The unique identifier of the skill version. Required. + :vartype id: str + :ivar skill_id: The identifier of the parent skill. Required. + :vartype skill_id: str + :ivar name: The name of the skill version. Required. + :vartype name: str + :ivar version: The version identifier. Skill versions are immutable. Required. + :vartype version: str + :ivar description: A human-readable description of the skill version. Required. + :vartype description: str + :ivar created_at: The Unix timestamp (seconds) when the skill version was created. Required. + :vartype created_at: ~datetime.datetime + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of the skill version. Required.""" + skill_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The identifier of the parent skill. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the skill version. Required.""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version identifier. Skill versions are immutable. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the skill version. Required.""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (seconds) when the skill version was created. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + skill_id: str, + name: str, + version: str, + description: str, + created_at: datetime.datetime, + ) -> 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 ToolChoiceParam(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """How the model should select which tool (or tools) to use when generating a response. See the + ``tools`` parameter to see how to specify which tools the model can call. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + ToolChoiceAllowed, SpecificApplyPatchParam, ToolChoiceCodeInterpreter, ToolChoiceComputer, + ToolChoiceComputerUse, ToolChoiceComputerUsePreview, ToolChoiceCustom, ToolChoiceFileSearch, + ToolChoiceFunction, ToolChoiceImageGeneration, ToolChoiceMCP, + SpecificProgrammaticToolCallingParam, SpecificFunctionShellParam, ToolChoiceWebSearchPreview, + ToolChoiceWebSearchPreview20250311 + + :ivar type: Required. Known values are: "allowed_tools", "function", "mcp", "custom", + "programmatic_tool_calling", "apply_patch", "shell", "file_search", "web_search_preview", + "computer_use_preview", "web_search_preview_2025_03_11", "image_generation", + "code_interpreter", "computer", and "computer_use". + :vartype type: str or ~azure.ai.projects.models.ToolChoiceParamType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"allowed_tools\", \"function\", \"mcp\", \"custom\", + \"programmatic_tool_calling\", \"apply_patch\", \"shell\", \"file_search\", + \"web_search_preview\", \"computer_use_preview\", \"web_search_preview_2025_03_11\", + \"image_generation\", \"code_interpreter\", \"computer\", and \"computer_use\".""" + + @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 SpecificApplyPatchParam(ToolChoiceParam, discriminator="apply_patch"): + """Specific apply patch tool choice. + + :ivar type: The tool to call. Always ``apply_patch``. Required. APPLY_PATCH. + :vartype type: str or ~azure.ai.projects.models.APPLY_PATCH + """ + + type: Literal[ToolChoiceParamType.APPLY_PATCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The tool to call. Always ``apply_patch``. Required. APPLY_PATCH.""" + + @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 = ToolChoiceParamType.APPLY_PATCH # type: ignore + + +class SpecificFunctionShellParam(ToolChoiceParam, discriminator="shell"): + """Specific shell tool choice. + + :ivar type: The tool to call. Always ``shell``. Required. SHELL. + :vartype type: str or ~azure.ai.projects.models.SHELL + """ + + type: Literal[ToolChoiceParamType.SHELL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The tool to call. Always ``shell``. Required. SHELL.""" + + @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 = ToolChoiceParamType.SHELL # type: ignore + + +class SpecificProgrammaticToolCallingParam(ToolChoiceParam, discriminator="programmatic_tool_calling"): + """SpecificProgrammaticToolCallingParam. + + :ivar type: The tool to call. Always ``programmatic_tool_calling``. Required. + PROGRAMMATIC_TOOL_CALLING. + :vartype type: str or ~azure.ai.projects.models.PROGRAMMATIC_TOOL_CALLING + """ + + type: Literal[ToolChoiceParamType.PROGRAMMATIC_TOOL_CALLING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The tool to call. Always ``programmatic_tool_calling``. Required. PROGRAMMATIC_TOOL_CALLING.""" + + @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 = ToolChoiceParamType.PROGRAMMATIC_TOOL_CALLING # type: ignore + + +class SteeringPromptOptimizationContext( + OptimizationContext, discriminator="steering_prompt" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Natural-language guidance for the desired optimization. + + :ivar type: Optimization context type discriminator. Required. Natural-language guidance that + steers the desired optimization. + :vartype type: str or ~azure.ai.projects.models.STEERING_PROMPT + :ivar prompt: Developer guidance describing the desired changes. Required. + :vartype prompt: str + """ + + type: Literal[OptimizationContextType.STEERING_PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Optimization context type discriminator. Required. Natural-language guidance that steers the + desired optimization.""" + prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Developer guidance describing the desired changes. Required.""" + + @overload + def __init__( + self, + *, + prompt: 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 = OptimizationContextType.STEERING_PROMPT # type: ignore + + +class StructuredInputDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An structured input that can participate in prompt template substitutions and tool argument + binding. + + :ivar description: A human-readable description of the input. + :vartype description: str + :ivar default_value: The default value for the input if no run-time value is provided. + :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. The service + defaults to ``false`` if a value is not specified by the caller. + :vartype required: bool + """ + + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the input.""" + default_value: Optional[Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The default value for the input if no run-time value is provided.""" + 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. The service defaults to + ``false`` if a value is not specified by the caller.""" + + @overload + def __init__( + self, + *, + description: Optional[str] = None, + default_value: Optional[Any] = None, + schema: Optional[dict[str, Any]] = None, + required: 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 StructuredOutputDefinition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A structured output that can be produced by the agent. + + :ivar name: The name of the structured output. Required. + :vartype name: str + :ivar description: A description of the output to emit. Used by the model to determine when to + emit the output. Required. + :vartype description: str + :ivar schema: The JSON schema for the structured output. Required. + :vartype schema: dict[str, any] + :ivar strict: Whether to enforce strict validation. Default ``true``. Required. + :vartype strict: bool + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the structured output. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description of the output to emit. Used by the model to determine when to emit the output. + Required.""" + schema: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The JSON schema for the structured output. Required.""" + strict: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to enforce strict validation. Default ``true``. Required.""" + + @overload + def __init__( + self, + *, + name: str, + description: str, + schema: dict[str, Any], + strict: bool, + ) -> 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 SupervisedFineTuningDataGenerationJob( + DataGenerationJob, discriminator="supervised_finetuning_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Supervised fine-tuning data generation job resource. This is a preview feature. + + :ivar id: Server-assigned unique identifier. Required. + :vartype id: str + :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 name: The display name of the data generation job. Required. + :vartype name: str + :ivar sources: The sources used for the data generation job. Required. + :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] + :ivar generation_configuration: The generation configuration for the data generation job. + Required. + :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration + :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds + since January 1, 1970). Required. + :vartype created_at: ~datetime.datetime + :ivar finished_at: The timestamp when the job was finished, represented in Unix time (seconds + since January 1, 1970). + :vartype finished_at: ~datetime.datetime + :ivar scenario: The scenario of the data generation job, which is Supervised Fine-tuning + preview for this model. Required. Supervised Fine-tuning preview scenario. + :vartype scenario: str or ~azure.ai.projects.models.SUPERVISED_FINETUNING_PREVIEW + :ivar output_configuration: Optional file output configuration for the generated supervised + fine-tuning data. + :vartype output_configuration: + ~azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration + """ + + scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The scenario of the data generation job, which is Supervised Fine-tuning preview for this + model. Required. Supervised Fine-tuning preview scenario.""" + output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional file output configuration for the generated supervised fine-tuning data.""" + + @overload + def __init__( + self, + *, + name: str, + sources: list["_models.DataGenerationJobSource"], + generation_configuration: "_models.DataGenerationJobConfiguration", + output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = 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.scenario = DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW # type: ignore + + +class SupervisedFineTuningDataGenerationJobInputs( + DataGenerationJobInputs, discriminator="supervised_finetuning_preview" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Caller-supplied inputs for a supervised fine-tuning data generation job. This is a preview + feature. + + :ivar name: The display name of the data generation job. Required. + :vartype name: str + :ivar sources: The sources used for the data generation job. Required. + :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] + :ivar generation_configuration: The generation configuration for the data generation job. + Required. + :vartype generation_configuration: ~azure.ai.projects.models.DataGenerationJobConfiguration + :ivar scenario: The scenario of the data generation job, which is Supervised Fine-tuning + preview for this model. Required. Supervised Fine-tuning preview scenario. + :vartype scenario: str or ~azure.ai.projects.models.SUPERVISED_FINETUNING_PREVIEW + :ivar output_configuration: Optional file output configuration for the generated supervised + fine-tuning data. + :vartype output_configuration: + ~azure.ai.projects.models.SupervisedFineTuningDataGenerationJobOutputConfiguration + """ + + scenario: Literal[DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW] = rest_discriminator(name="scenario", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The scenario of the data generation job, which is Supervised Fine-tuning preview for this + model. Required. Supervised Fine-tuning preview scenario.""" + output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional file output configuration for the generated supervised fine-tuning data.""" + + @overload + def __init__( + self, + *, + name: str, + sources: list["_models.DataGenerationJobSource"], + generation_configuration: "_models.DataGenerationJobConfiguration", + output_configuration: Optional["_models.SupervisedFineTuningDataGenerationJobOutputConfiguration"] = 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.scenario = DataGenerationJobScenario.SUPERVISED_FINETUNING_PREVIEW # type: ignore + + +class SupervisedFineTuningDataGenerationJobOutputConfiguration( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """File output configuration for a supervised fine-tuning data generation job. This is a preview + feature. + + :ivar name: Filename to assign to the generated fine-tuning file. Required. + :vartype name: str + :ivar write_mode: Controls how file outputs are written. If omitted, defaults to ``overwrite`` + and writes only the newly generated fine-tuning file content. Known values are: "overwrite" and + "merge". + :vartype write_mode: str or ~azure.ai.projects.models.DataGenerationJobOutputWriteMode + :ivar merge_file_id: File ID to merge into when ``write_mode`` is ``merge``. + :vartype merge_file_id: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Filename to assign to the generated fine-tuning file. Required.""" + write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Controls how file outputs are written. If omitted, defaults to ``overwrite`` and writes only + the newly generated fine-tuning file content. Known values are: \"overwrite\" and \"merge\".""" + merge_file_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """File ID to merge into when ``write_mode`` is ``merge``.""" + + @overload + def __init__( + self, + *, + name: str, + write_mode: Optional[Union[str, "_models.DataGenerationJobOutputWriteMode"]] = None, + merge_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 TaxonomyCategory(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Taxonomy category definition. + + :ivar id: Unique identifier of the taxonomy category. Required. + :vartype id: str + :ivar name: Name of the taxonomy category. Required. + :vartype name: str + :ivar description: Description of the taxonomy category. + :vartype description: str + :ivar risk_category: Risk category associated with this taxonomy category. Required. Known + values are: "HateUnfairness", "Violence", "Sexual", "SelfHarm", "ProtectedMaterial", + "CodeVulnerability", "UngroundedAttributes", "ProhibitedActions", "SensitiveDataLeakage", and + "TaskAdherence". + :vartype risk_category: str or ~azure.ai.projects.models.RiskCategory + :ivar sub_categories: List of taxonomy sub categories. Required. + :vartype sub_categories: list[~azure.ai.projects.models.TaxonomySubCategory] + :ivar properties: Additional properties for the taxonomy category. + :vartype properties: dict[str, str] + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Unique identifier of the taxonomy category. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name of the taxonomy category. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description of the taxonomy category.""" + risk_category: Union[str, "_models.RiskCategory"] = rest_field( + name="riskCategory", visibility=["read", "create", "update", "delete", "query"] + ) + """Risk category associated with this taxonomy category. Required. Known values are: + \"HateUnfairness\", \"Violence\", \"Sexual\", \"SelfHarm\", \"ProtectedMaterial\", + \"CodeVulnerability\", \"UngroundedAttributes\", \"ProhibitedActions\", + \"SensitiveDataLeakage\", and \"TaskAdherence\".""" + sub_categories: list["_models.TaxonomySubCategory"] = rest_field( + name="subCategories", visibility=["read", "create", "update", "delete", "query"] + ) + """List of taxonomy sub categories. Required.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Additional properties for the taxonomy category.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + name: str, + risk_category: Union[str, "_models.RiskCategory"], + sub_categories: list["_models.TaxonomySubCategory"], + description: Optional[str] = None, + properties: 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 TaxonomySubCategory(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Taxonomy sub-category definition. + + :ivar id: Unique identifier of the taxonomy sub-category. Required. + :vartype id: str + :ivar name: Name of the taxonomy sub-category. Required. + :vartype name: str + :ivar description: Description of the taxonomy sub-category. + :vartype description: str + :ivar enabled: List of taxonomy items under this sub-category. Required. + :vartype enabled: bool + :ivar properties: Additional properties for the taxonomy sub-category. + :vartype properties: dict[str, str] + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Unique identifier of the taxonomy sub-category. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name of the taxonomy sub-category. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Description of the taxonomy sub-category.""" + enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """List of taxonomy items under this sub-category. Required.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Additional properties for the taxonomy sub-category.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + name: str, + enabled: bool, + description: Optional[str] = None, + properties: 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 TeamsAddress( + TelephonyAddress, discriminator="teams" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Teams source/transfer identity, validated by role and provider. Not supported for outbound + recipients. + + :ivar type: The Microsoft Teams address type. Required. A Microsoft Teams identity. Source + addresses require a nonempty resource-account object GUID; transfer destinations also support + 28:orgid:{guid}. + :vartype type: str or ~azure.ai.projects.models.TEAMS + :ivar value: Source: nonempty resource-account GUID. Transfer: user/resource-account GUID or + 28:orgid:{guid}. Required. + :vartype value: str + """ + + type: Literal[TelephonyAddressType.TEAMS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Microsoft Teams address type. Required. A Microsoft Teams identity. Source addresses + require a nonempty resource-account object GUID; transfer destinations also support + 28:orgid:{guid}.""" + + @overload + def __init__( + self, + *, + value: 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 = TelephonyAddressType.TEAMS # type: ignore + + +class TeamsPhoneExtensibilityTelephonyBinding( + TelephonyBinding, discriminator="teams_phone_extensibility" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Microsoft Teams Phone extensibility binding owned by a voice agent. + + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated incoming address: an HTTPS webhook for + webhook-based providers or a SIP/SIPS ingress URI for SIP. Required. + :vartype incoming_call_url: str + :ivar provider: The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams + Phone extensibility. + :vartype provider: str or ~azure.ai.projects.models.TEAMS_PHONE_EXTENSIBILITY + :ivar phone_number: The optional display phone number for the Teams resource account. + :vartype phone_number: str + :ivar resource_account_object_id: The Microsoft Teams resource-account object identifier as a + GUID. Required. + :vartype resource_account_object_id: str + """ + + provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams Phone + extensibility.""" + phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The optional display phone number for the Teams resource account.""" + resource_account_object_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Microsoft Teams resource-account object identifier as a GUID. Required.""" + + @overload + def __init__( + self, + *, + connection_name: str, + resource_account_object_id: str, + label: Optional[str] = None, + phone_number: 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.provider = TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY # type: ignore + + +class TeamsPhoneExtensibilityTelephonyBindingListItem( + TelephonyBindingListItem, discriminator="teams_phone_extensibility" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """A Microsoft Teams Phone extensibility binding returned in a list, including its entity tag. + + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated HTTPS webhook or SIP/SIPS ingress URI to + configure with the telephony provider. Required. + :vartype incoming_call_url: str + :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this + binding. Required. + :vartype etag: str + :ivar provider: The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams + Phone extensibility. + :vartype provider: str or ~azure.ai.projects.models.TEAMS_PHONE_EXTENSIBILITY + :ivar phone_number: The optional display phone number for the Teams resource account. + :vartype phone_number: str + :ivar resource_account_object_id: The Microsoft Teams resource-account object identifier as a + GUID. Required. + :vartype resource_account_object_id: str + """ + + provider: Literal[TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Microsoft Teams Phone extensibility provider. Required. Microsoft Teams Phone + extensibility.""" + phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The optional display phone number for the Teams resource account.""" + resource_account_object_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Microsoft Teams resource-account object identifier as a GUID. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + connection_name: str, + incoming_call_url: str, + resource_account_object_id: str, + label: Optional[str] = None, + phone_number: 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.provider = TelephonyProvider.TEAMS_PHONE_EXTENSIBILITY # type: ignore + + +class TelemetryConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Customer-supplied telemetry configuration for exporting container logs, traces, and metrics. + + :ivar endpoints: Customer-supplied telemetry export endpoint configurations. Required. + :vartype endpoints: list[~azure.ai.projects.models.TelemetryEndpoint] + """ + + endpoints: list["_models.TelemetryEndpoint"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Customer-supplied telemetry export endpoint configurations. Required.""" + + @overload + def __init__( + self, + *, + endpoints: list["_models.TelemetryEndpoint"], + ) -> 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 TelephonyCallJob(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A durable direct or campaign-created outbound call intent. + + :ivar destination: The phone destination to call. Required. + :vartype destination: ~azure.ai.projects.models.TelephonyAddress + :ivar connection_name: Same-project Twilio, ACS/Teams Phone extensibility or SipOutbound + connection; no inbound binding needed. SIP requires CustomKeys and a DNS target, revalidated + before dialing, not a connectivity guarantee. Required. + :vartype connection_name: str + :ivar purpose: An optional customer-declared purpose for placing the call. + :vartype purpose: str + :ivar structured_inputs: Agent/greeting inputs, including nested JSON and null. Agent schemas, + required fields and defaults apply. + :vartype structured_inputs: dict[str, any] + :ivar schedule: The optional execution window. + :vartype schedule: ~azure.ai.projects.models.TelephonyCallJobSchedule + :ivar id: The service-generated call-job identifier. Required. + :vartype id: str + :ivar agent_name: The name of the voice agent used at execution time. Required. + :vartype agent_name: str + :ivar status: The current call-job lifecycle status. Required. Known values are: "accepted", + "waiting_for_schedule", "queued", "dispatching", "in_progress", "waiting_for_retry", + "cancellation_requested", "completed", "blocked", "expired", "failed", and "cancelled". + :vartype status: str or ~azure.ai.projects.models.TelephonyCallJobStatus + :ivar cancellation: The recorded cancellation request, when cancellation was requested. + :vartype cancellation: ~azure.ai.projects.models.TelephonyCallJobCancellation + :ivar retry_policy: Frozen retry policy. Omission at creation returns fixed_interval with + max_attempts=1 and interval=0 seconds: one initial attempt, no retry. Required. + :vartype retry_policy: ~azure.ai.projects.models.TelephonyOutboundRetryPolicy + :ivar attempt_count: The number of provider attempts created so far. Required. + :vartype attempt_count: int + :ivar next_attempt_at: The Unix timestamp in seconds at which the next retry becomes eligible. + :vartype next_attempt_at: ~datetime.datetime + :ivar terminal_reason: The stable service-generated reason for the overall outbound call job, + which can span multiple provider attempts, when available. Interpret this with ``status``: a + queued job can retain a temporary dispatch-deferral reason. Additional string codes may be + returned. Known values are: "no_answer", "no_answer_timeout", "answer_failed", + "bridge_cancelled", "bridge_failed", "voice_session_configuration_invalid", + "connection_project_mismatch", "outbound_connection_changed", + "outbound_connection_unavailable", "telephony_binding_invalid", "telephony_binding_not_found", + "telephony_binding_inactive", "telephony_binding_changed", "campaign_not_found", + "campaign_cancelled", "campaign_completed", "campaign_failed", + "origination_fence_not_recorded", "origination_reconciliation_timeout", + "cancellation_reconciliation_timeout", and + "provider_callback_timeout_cancellation_reconciliation_timeout". + :vartype terminal_reason: str or ~azure.ai.projects.models.TelephonyCallJobTerminalReason + :ivar revision: The monotonically increasing optimistic-concurrency revision. Required. + :vartype revision: int + :ivar created_at: The Unix timestamp in seconds when the call job was created. Required. + :vartype created_at: ~datetime.datetime + :ivar updated_at: The Unix timestamp in seconds when the call job was last updated. Required. + :vartype updated_at: ~datetime.datetime + :ivar source: Caller identity: phone_number for Twilio/SIP, or a teams resource-account GUID + for ACS/Teams Phone extensibility. No sip source URI. Required. + :vartype source: ~azure.ai.projects.models.TelephonyAddress + :ivar campaign_name: Owning Campaign, absent for direct calls. Instance-bound despite name + reuse; Campaign deletion hides then removes its jobs. + :vartype campaign_name: str + """ + + destination: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The phone destination to call. Required.""" + connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Same-project Twilio, ACS/Teams Phone extensibility or SipOutbound connection; no inbound + binding needed. SIP requires CustomKeys and a DNS target, revalidated before dialing, not a + connectivity guarantee. Required.""" + purpose: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional customer-declared purpose for placing the call.""" + structured_inputs: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Agent/greeting inputs, including nested JSON and null. Agent schemas, required fields and + defaults apply.""" + schedule: Optional["_models.TelephonyCallJobSchedule"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The optional execution window.""" + id: str = rest_field(visibility=["read"]) + """The service-generated call-job identifier. Required.""" + agent_name: str = rest_field(visibility=["read"]) + """The name of the voice agent used at execution time. Required.""" + status: Union[str, "_models.TelephonyCallJobStatus"] = rest_field(visibility=["read"]) + """The current call-job lifecycle status. Required. Known values are: \"accepted\", + \"waiting_for_schedule\", \"queued\", \"dispatching\", \"in_progress\", \"waiting_for_retry\", + \"cancellation_requested\", \"completed\", \"blocked\", \"expired\", \"failed\", and + \"cancelled\".""" + cancellation: Optional["_models.TelephonyCallJobCancellation"] = rest_field(visibility=["read"]) + """The recorded cancellation request, when cancellation was requested.""" + retry_policy: "_models.TelephonyOutboundRetryPolicy" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Frozen retry policy. Omission at creation returns fixed_interval with max_attempts=1 and + interval=0 seconds: one initial attempt, no retry. Required.""" + attempt_count: int = rest_field(visibility=["read"]) + """The number of provider attempts created so far. Required.""" + next_attempt_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp in seconds at which the next retry becomes eligible.""" + terminal_reason: Optional[Union[str, "_models.TelephonyCallJobTerminalReason"]] = rest_field(visibility=["read"]) + """The stable service-generated reason for the overall outbound call job, which can span multiple + provider attempts, when available. Interpret this with ``status``: a queued job can retain a + temporary dispatch-deferral reason. Additional string codes may be returned. Known values are: + \"no_answer\", \"no_answer_timeout\", \"answer_failed\", \"bridge_cancelled\", + \"bridge_failed\", \"voice_session_configuration_invalid\", \"connection_project_mismatch\", + \"outbound_connection_changed\", \"outbound_connection_unavailable\", + \"telephony_binding_invalid\", \"telephony_binding_not_found\", \"telephony_binding_inactive\", + \"telephony_binding_changed\", \"campaign_not_found\", \"campaign_cancelled\", + \"campaign_completed\", \"campaign_failed\", \"origination_fence_not_recorded\", + \"origination_reconciliation_timeout\", \"cancellation_reconciliation_timeout\", and + \"provider_callback_timeout_cancellation_reconciliation_timeout\".""" + revision: int = rest_field(visibility=["read"]) + """The monotonically increasing optimistic-concurrency revision. Required.""" + created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp in seconds when the call job was created. Required.""" + updated_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp in seconds when the call job was last updated. Required.""" + source: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Caller identity: phone_number for Twilio/SIP, or a teams resource-account GUID for ACS/Teams + Phone extensibility. No sip source URI. Required.""" + campaign_name: Optional[str] = rest_field(visibility=["read"]) + """Owning Campaign, absent for direct calls. Instance-bound despite name reuse; Campaign deletion + hides then removes its jobs.""" + + @overload + def __init__( + self, + *, + destination: "_models.TelephonyAddress", + connection_name: str, + retry_policy: "_models.TelephonyOutboundRetryPolicy", + source: "_models.TelephonyAddress", + purpose: Optional[str] = None, + structured_inputs: Optional[dict[str, Any]] = None, + schedule: Optional["_models.TelephonyCallJobSchedule"] = 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 TelephonyCallJobCancellation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A cancellation request recorded for an outbound call job. + + :ivar requested_by: The authenticated principal that requested cancellation. Required. + :vartype requested_by: str + :ivar mode: The cancellation mode applied to the call job. Required. + :vartype mode: str + :ivar requested_at: The Unix timestamp in seconds when cancellation was requested. Required. + :vartype requested_at: ~datetime.datetime + :ivar revision: The call-job revision at which cancellation was recorded. Required. + :vartype revision: int + """ + + requested_by: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The authenticated principal that requested cancellation. Required.""" + mode: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The cancellation mode applied to the call job. Required.""" + requested_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp in seconds when cancellation was requested. Required.""" + revision: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The call-job revision at which cancellation was recorded. Required.""" + + @overload + def __init__( + self, + *, + requested_by: str, + mode: str, + requested_at: datetime.datetime, + revision: 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 TelephonyCallJobCreate(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The direct outbound call to create. + + :ivar destination: The phone destination to call. Required. + :vartype destination: ~azure.ai.projects.models.TelephonyAddress + :ivar connection_name: Same-project Twilio, ACS/Teams Phone extensibility or SipOutbound + connection; no inbound binding needed. SIP requires CustomKeys and a DNS target, revalidated + before dialing, not a connectivity guarantee. Required. + :vartype connection_name: str + :ivar purpose: An optional customer-declared purpose for placing the call. + :vartype purpose: str + :ivar structured_inputs: Agent/greeting inputs, including nested JSON and null. Agent schemas, + required fields and defaults apply. + :vartype structured_inputs: dict[str, any] + :ivar schedule: The optional execution window. + :vartype schedule: ~azure.ai.projects.models.TelephonyCallJobSchedule + :ivar retry_policy: Frozen retry policy. Omission at creation returns fixed_interval with + max_attempts=1 and interval=0 seconds: one initial attempt, no retry. + :vartype retry_policy: ~azure.ai.projects.models.TelephonyOutboundRetryPolicy + :ivar source: Caller identity: phone_number for Twilio/SIP, or a teams resource-account GUID + for ACS/Teams Phone extensibility. No sip source URI. Required. + :vartype source: ~azure.ai.projects.models.TelephonyAddress + """ + + destination: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The phone destination to call. Required.""" + connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Same-project Twilio, ACS/Teams Phone extensibility or SipOutbound connection; no inbound + binding needed. SIP requires CustomKeys and a DNS target, revalidated before dialing, not a + connectivity guarantee. Required.""" + purpose: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional customer-declared purpose for placing the call.""" + structured_inputs: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Agent/greeting inputs, including nested JSON and null. Agent schemas, required fields and + defaults apply.""" + schedule: Optional["_models.TelephonyCallJobSchedule"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The optional execution window.""" + retry_policy: Optional["_models.TelephonyOutboundRetryPolicy"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Frozen retry policy. Omission at creation returns fixed_interval with max_attempts=1 and + interval=0 seconds: one initial attempt, no retry.""" + source: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Caller identity: phone_number for Twilio/SIP, or a teams resource-account GUID for ACS/Teams + Phone extensibility. No sip source URI. Required.""" + + @overload + def __init__( + self, + *, + destination: "_models.TelephonyAddress", + connection_name: str, + source: "_models.TelephonyAddress", + purpose: Optional[str] = None, + structured_inputs: Optional[dict[str, Any]] = None, + schedule: Optional["_models.TelephonyCallJobSchedule"] = None, + retry_policy: Optional["_models.TelephonyOutboundRetryPolicy"] = 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 TelephonyCallJobSchedule(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The optional execution window for a direct outbound call. + + :ivar not_before: The earliest instant at which dispatch may begin. + :vartype not_before: ~datetime.datetime + :ivar expires_at: The instant after which the call job expires without dispatch. + :vartype expires_at: ~datetime.datetime + """ + + not_before: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The earliest instant at which dispatch may begin.""" + expires_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The instant after which the call job expires without dispatch.""" + + @overload + def __init__( + self, + *, + not_before: Optional[datetime.datetime] = None, + expires_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 TelephonyCallLifecycleEvent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A bounded durable observation in the lifecycle of one telephony call. + + :ivar sequence: The service-assigned order of the event within the call record. Required. + :vartype sequence: int + :ivar name: The stable provider-neutral event name. Required. Known values are: + "telephony.webhook.received", "telephony.webhook.validation", "telephony.binding.resolve", + "telephony.provider.answer", "telephony.media.connect", "telephony.agent_session.connect", + "telephony.media.first_caller_audio", "telephony.media.first_agent_audio", + "telephony.call.transfer", "telephony.call.hangup", and "telephony.call.disconnect". + :vartype name: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventName + :ivar source: The component that supplied the observation. Required. Known values are: + "gateway", "teams_phone_extensibility", "twilio", and "voice_agent". + :vartype source: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventSource + :ivar outcome: The outcome of the observed lifecycle operation. Required. Known values are: + "observed", "started", "succeeded", "failed", "rejected", and "cancelled". + :vartype outcome: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventOutcome + :ivar observed_at: The Unix timestamp (in seconds) for when the service observed the event. + Required. + :vartype observed_at: ~datetime.datetime + :ivar occurred_at: The Unix timestamp (in seconds) for when the event occurred according to the + provider. + :vartype occurred_at: ~datetime.datetime + :ivar timestamp_source: The source of the event timestamp. Required. Known values are: + "provider", "gateway", and "derived". + :vartype timestamp_source: str or ~azure.ai.projects.models.TelephonyCallTimestampSource + :ivar reason: A stable service-generated reason associated with this lifecycle event, not + necessarily the final outcome of the call. Additional string codes may be returned. Known + values are: "invalid_webhook_payload", "webhook_validation_failed", "binding_not_found", + "binding_suspended", "admission_rejected", "admission_check_failed", "route_agent_mismatch", + "invalid_binding_configuration", "credential_resolution_failed", "provider_resource_mismatch", + "endpoint_resolution_failed", "ingress_setup_failed", "live_call_conflict", + "live_call_persistence_failed", "answer_failed", "provider_disconnected", "provider_busy", + "provider_no_answer", "provider_cancelled", "provider_failed", "provider_stream_error", + "provider_stream_stopped", "agent_session_connect_failed", "media_stream_ended", + "bridge_cancelled", "bridge_failed", "managed_hangup", "managed_transfer", + "manage_hangup_failed", and "manage_transfer_failed". + :vartype reason: str or ~azure.ai.projects.models.TelephonyCallLifecycleEventReason + :ivar provider_event_id: The provider event identifier used for idempotency, when supplied. + :vartype provider_event_id: str + :ivar provider_sequence: The provider event sequence, when supplied. + :vartype provider_sequence: int + :ivar provider_status_code: The provider status code associated with the event. + :vartype provider_status_code: int + :ivar provider_sub_code: The provider subcode associated with the event. + :vartype provider_sub_code: int + """ + + sequence: int = rest_field(visibility=["read"]) + """The service-assigned order of the event within the call record. Required.""" + name: Union[str, "_models.TelephonyCallLifecycleEventName"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The stable provider-neutral event name. Required. Known values are: + \"telephony.webhook.received\", \"telephony.webhook.validation\", + \"telephony.binding.resolve\", \"telephony.provider.answer\", \"telephony.media.connect\", + \"telephony.agent_session.connect\", \"telephony.media.first_caller_audio\", + \"telephony.media.first_agent_audio\", \"telephony.call.transfer\", \"telephony.call.hangup\", + and \"telephony.call.disconnect\".""" + source: Union[str, "_models.TelephonyCallLifecycleEventSource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The component that supplied the observation. Required. Known values are: \"gateway\", + \"teams_phone_extensibility\", \"twilio\", and \"voice_agent\".""" + outcome: Union[str, "_models.TelephonyCallLifecycleEventOutcome"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The outcome of the observed lifecycle operation. Required. Known values are: \"observed\", + \"started\", \"succeeded\", \"failed\", \"rejected\", and \"cancelled\".""" + observed_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the service observed the event. Required.""" + occurred_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the event occurred according to the provider.""" + timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The source of the event timestamp. Required. Known values are: \"provider\", \"gateway\", and + \"derived\".""" + reason: Optional[Union[str, "_models.TelephonyCallLifecycleEventReason"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """A stable service-generated reason associated with this lifecycle event, not necessarily the + final outcome of the call. Additional string codes may be returned. Known values are: + \"invalid_webhook_payload\", \"webhook_validation_failed\", \"binding_not_found\", + \"binding_suspended\", \"admission_rejected\", \"admission_check_failed\", + \"route_agent_mismatch\", \"invalid_binding_configuration\", \"credential_resolution_failed\", + \"provider_resource_mismatch\", \"endpoint_resolution_failed\", \"ingress_setup_failed\", + \"live_call_conflict\", \"live_call_persistence_failed\", \"answer_failed\", + \"provider_disconnected\", \"provider_busy\", \"provider_no_answer\", \"provider_cancelled\", + \"provider_failed\", \"provider_stream_error\", \"provider_stream_stopped\", + \"agent_session_connect_failed\", \"media_stream_ended\", \"bridge_cancelled\", + \"bridge_failed\", \"managed_hangup\", \"managed_transfer\", \"manage_hangup_failed\", and + \"manage_transfer_failed\".""" + provider_event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider event identifier used for idempotency, when supplied.""" + provider_sequence: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider event sequence, when supplied.""" + provider_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider status code associated with the event.""" + provider_sub_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider subcode associated with the event.""" + + @overload + def __init__( + self, + *, + name: Union[str, "_models.TelephonyCallLifecycleEventName"], + source: Union[str, "_models.TelephonyCallLifecycleEventSource"], + outcome: Union[str, "_models.TelephonyCallLifecycleEventOutcome"], + observed_at: datetime.datetime, + timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"], + occurred_at: Optional[datetime.datetime] = None, + reason: Optional[Union[str, "_models.TelephonyCallLifecycleEventReason"]] = None, + provider_event_id: Optional[str] = None, + provider_sequence: Optional[int] = None, + provider_status_code: Optional[int] = None, + provider_sub_code: 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 TelephonyCallRecord(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Detailed diagnostics for a durable inbound call to a voice agent. + + :ivar id: The service-generated call identifier. Required. + :vartype id: str + :ivar provider: The telephony provider. Required. Known values are: + "teams_phone_extensibility", "twilio", and "sip". + :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider + :ivar provider_call_id: The provider-assigned call identifier, when available. + :vartype provider_call_id: str + :ivar caller_number: The caller's phone number, when supplied by the provider. + :vartype caller_number: str + :ivar provider_number: The Teams Phone extensibility or Twilio number that received the call. + :vartype provider_number: str + :ivar status: The lifecycle status of the call. Required. Known values are: "in_progress", + "success", and "failed". + :vartype status: str or ~azure.ai.projects.models.TelephonyCallStatus + :ivar phase: The provider-neutral lifecycle phase reached by the call. Required. Known values + are: "received", "validated", "admitted", "answering", "answered", "media_connected", + "agent_session_ready", "bridging", "managing", "completed", "rejected", and "failed". + :vartype phase: str or ~azure.ai.projects.models.TelephonyCallPhase + :ivar started_at: The Unix timestamp (in seconds) for when the inbound webhook was received. + Required. + :vartype started_at: ~datetime.datetime + :ivar answered_at: The Unix timestamp (in seconds) for when the provider reported the call as + answered. + :vartype answered_at: ~datetime.datetime + :ivar media_connected_at: The Unix timestamp (in seconds) for when the provider media channel + connected. + :vartype media_connected_at: ~datetime.datetime + :ivar agent_session_ready_at: The Unix timestamp (in seconds) for when the voice-agent session + became ready. + :vartype agent_session_ready_at: ~datetime.datetime + :ivar ended_at: The Unix timestamp (in seconds) for when the call ended. + :vartype ended_at: ~datetime.datetime + :ivar duration_ms: The call duration. + :vartype duration_ms: ~datetime.timedelta + :ivar end_reason: The service-generated reason that this single call ended, rather than the + outcome of an overall outbound call job. Additional string codes may be returned. Known values + are: "invalid_webhook_payload", "webhook_validation_failed", "binding_not_found", + "binding_suspended", "admission_rejected", "admission_check_failed", "route_agent_mismatch", + "invalid_binding_configuration", "credential_resolution_failed", "provider_resource_mismatch", + "endpoint_resolution_failed", "ingress_setup_failed", "live_call_conflict", + "live_call_persistence_failed", "answer_failed", "provider_disconnected", "provider_busy", + "provider_no_answer", "provider_cancelled", "provider_failed", "provider_stream_error", + "provider_stream_stopped", "agent_session_connect_failed", "media_stream_ended", + "bridge_cancelled", "bridge_failed", "managed_hangup", "managed_transfer", + "manage_hangup_failed", and "manage_transfer_failed". + :vartype end_reason: str or ~azure.ai.projects.models.TelephonyCallEndReason + :ivar provider_status_code: The provider status code associated with the terminal result. + :vartype provider_status_code: int + :ivar provider_sub_code: The provider subcode associated with the terminal result. + :vartype provider_sub_code: int + :ivar provider_message: The provider message associated with the terminal result. + :vartype provider_message: str + :ivar timing: Detailed provider-neutral call timing. Required. + :vartype timing: ~azure.ai.projects.models.TelephonyCallTiming + :ivar trace: Correlation to the customer-facing Foundry trace. + :vartype trace: ~azure.ai.projects.models.TelephonyCallTrace + :ivar events: The lifecycle timeline. Required. + :vartype events: list[~azure.ai.projects.models.TelephonyCallLifecycleEvent] + :ivar events_truncated: Whether older lifecycle events were omitted from the timeline. + Required. + :vartype events_truncated: bool + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The service-generated call identifier. Required.""" + provider: Union[str, "_models.TelephonyProvider"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The telephony provider. Required. Known values are: \"teams_phone_extensibility\", \"twilio\", + and \"sip\".""" + provider_call_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider-assigned call identifier, when available.""" + caller_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The caller's phone number, when supplied by the provider.""" + provider_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Teams Phone extensibility or Twilio number that received the call.""" + status: Union[str, "_models.TelephonyCallStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The lifecycle status of the call. Required. Known values are: \"in_progress\", \"success\", and + \"failed\".""" + phase: Union[str, "_models.TelephonyCallPhase"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The provider-neutral lifecycle phase reached by the call. Required. Known values are: + \"received\", \"validated\", \"admitted\", \"answering\", \"answered\", \"media_connected\", + \"agent_session_ready\", \"bridging\", \"managing\", \"completed\", \"rejected\", and + \"failed\".""" + started_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the inbound webhook was received. Required.""" + answered_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider reported the call as answered.""" + media_connected_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider media channel connected.""" + agent_session_ready_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the voice-agent session became ready.""" + ended_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the call ended.""" + duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """The call duration.""" + end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The service-generated reason that this single call ended, rather than the outcome of an overall + outbound call job. Additional string codes may be returned. Known values are: + \"invalid_webhook_payload\", \"webhook_validation_failed\", \"binding_not_found\", + \"binding_suspended\", \"admission_rejected\", \"admission_check_failed\", + \"route_agent_mismatch\", \"invalid_binding_configuration\", \"credential_resolution_failed\", + \"provider_resource_mismatch\", \"endpoint_resolution_failed\", \"ingress_setup_failed\", + \"live_call_conflict\", \"live_call_persistence_failed\", \"answer_failed\", + \"provider_disconnected\", \"provider_busy\", \"provider_no_answer\", \"provider_cancelled\", + \"provider_failed\", \"provider_stream_error\", \"provider_stream_stopped\", + \"agent_session_connect_failed\", \"media_stream_ended\", \"bridge_cancelled\", + \"bridge_failed\", \"managed_hangup\", \"managed_transfer\", \"manage_hangup_failed\", and + \"manage_transfer_failed\".""" + provider_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider status code associated with the terminal result.""" + provider_sub_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider subcode associated with the terminal result.""" + provider_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider message associated with the terminal result.""" + timing: "_models.TelephonyCallTiming" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Detailed provider-neutral call timing. Required.""" + trace: Optional["_models.TelephonyCallTrace"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Correlation to the customer-facing Foundry trace.""" + events: list["_models.TelephonyCallLifecycleEvent"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The lifecycle timeline. Required.""" + events_truncated: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether older lifecycle events were omitted from the timeline. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + provider: Union[str, "_models.TelephonyProvider"], + status: Union[str, "_models.TelephonyCallStatus"], + phase: Union[str, "_models.TelephonyCallPhase"], + started_at: datetime.datetime, + timing: "_models.TelephonyCallTiming", + events: list["_models.TelephonyCallLifecycleEvent"], + events_truncated: bool, + provider_call_id: Optional[str] = None, + caller_number: Optional[str] = None, + provider_number: Optional[str] = None, + answered_at: Optional[datetime.datetime] = None, + media_connected_at: Optional[datetime.datetime] = None, + agent_session_ready_at: Optional[datetime.datetime] = None, + ended_at: Optional[datetime.datetime] = None, + duration_ms: Optional[datetime.timedelta] = None, + end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = None, + provider_status_code: Optional[int] = None, + provider_sub_code: Optional[int] = None, + provider_message: Optional[str] = None, + trace: Optional["_models.TelephonyCallTrace"] = 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 TelephonyCallSummary(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A summary of a durable inbound call to a voice agent. + + :ivar id: The service-generated call identifier. Required. + :vartype id: str + :ivar provider: The telephony provider. Required. Known values are: + "teams_phone_extensibility", "twilio", and "sip". + :vartype provider: str or ~azure.ai.projects.models.TelephonyProvider + :ivar provider_call_id: The provider-assigned call identifier, when available. + :vartype provider_call_id: str + :ivar caller_number: The caller's phone number, when supplied by the provider. + :vartype caller_number: str + :ivar provider_number: The Teams Phone extensibility or Twilio number that received the call. + :vartype provider_number: str + :ivar status: The lifecycle status of the call. Required. Known values are: "in_progress", + "success", and "failed". + :vartype status: str or ~azure.ai.projects.models.TelephonyCallStatus + :ivar phase: The provider-neutral lifecycle phase reached by the call. Required. Known values + are: "received", "validated", "admitted", "answering", "answered", "media_connected", + "agent_session_ready", "bridging", "managing", "completed", "rejected", and "failed". + :vartype phase: str or ~azure.ai.projects.models.TelephonyCallPhase + :ivar started_at: The Unix timestamp (in seconds) for when the inbound webhook was received. + Required. + :vartype started_at: ~datetime.datetime + :ivar answered_at: The Unix timestamp (in seconds) for when the provider reported the call as + answered. + :vartype answered_at: ~datetime.datetime + :ivar media_connected_at: The Unix timestamp (in seconds) for when the provider media channel + connected. + :vartype media_connected_at: ~datetime.datetime + :ivar agent_session_ready_at: The Unix timestamp (in seconds) for when the voice-agent session + became ready. + :vartype agent_session_ready_at: ~datetime.datetime + :ivar ended_at: The Unix timestamp (in seconds) for when the call ended. + :vartype ended_at: ~datetime.datetime + :ivar duration_ms: The call duration. + :vartype duration_ms: ~datetime.timedelta + :ivar end_reason: The service-generated reason that this single call ended, rather than the + outcome of an overall outbound call job. Additional string codes may be returned. Known values + are: "invalid_webhook_payload", "webhook_validation_failed", "binding_not_found", + "binding_suspended", "admission_rejected", "admission_check_failed", "route_agent_mismatch", + "invalid_binding_configuration", "credential_resolution_failed", "provider_resource_mismatch", + "endpoint_resolution_failed", "ingress_setup_failed", "live_call_conflict", + "live_call_persistence_failed", "answer_failed", "provider_disconnected", "provider_busy", + "provider_no_answer", "provider_cancelled", "provider_failed", "provider_stream_error", + "provider_stream_stopped", "agent_session_connect_failed", "media_stream_ended", + "bridge_cancelled", "bridge_failed", "managed_hangup", "managed_transfer", + "manage_hangup_failed", and "manage_transfer_failed". + :vartype end_reason: str or ~azure.ai.projects.models.TelephonyCallEndReason + :ivar provider_status_code: The provider status code associated with the terminal result. + :vartype provider_status_code: int + :ivar provider_sub_code: The provider subcode associated with the terminal result. + :vartype provider_sub_code: int + :ivar provider_message: The provider message associated with the terminal result. + :vartype provider_message: str + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The service-generated call identifier. Required.""" + provider: Union[str, "_models.TelephonyProvider"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The telephony provider. Required. Known values are: \"teams_phone_extensibility\", \"twilio\", + and \"sip\".""" + provider_call_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider-assigned call identifier, when available.""" + caller_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The caller's phone number, when supplied by the provider.""" + provider_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Teams Phone extensibility or Twilio number that received the call.""" + status: Union[str, "_models.TelephonyCallStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The lifecycle status of the call. Required. Known values are: \"in_progress\", \"success\", and + \"failed\".""" + phase: Union[str, "_models.TelephonyCallPhase"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The provider-neutral lifecycle phase reached by the call. Required. Known values are: + \"received\", \"validated\", \"admitted\", \"answering\", \"answered\", \"media_connected\", + \"agent_session_ready\", \"bridging\", \"managing\", \"completed\", \"rejected\", and + \"failed\".""" + started_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the inbound webhook was received. Required.""" + answered_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider reported the call as answered.""" + media_connected_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider media channel connected.""" + agent_session_ready_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the voice-agent session became ready.""" + ended_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the call ended.""" + duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """The call duration.""" + end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The service-generated reason that this single call ended, rather than the outcome of an overall + outbound call job. Additional string codes may be returned. Known values are: + \"invalid_webhook_payload\", \"webhook_validation_failed\", \"binding_not_found\", + \"binding_suspended\", \"admission_rejected\", \"admission_check_failed\", + \"route_agent_mismatch\", \"invalid_binding_configuration\", \"credential_resolution_failed\", + \"provider_resource_mismatch\", \"endpoint_resolution_failed\", \"ingress_setup_failed\", + \"live_call_conflict\", \"live_call_persistence_failed\", \"answer_failed\", + \"provider_disconnected\", \"provider_busy\", \"provider_no_answer\", \"provider_cancelled\", + \"provider_failed\", \"provider_stream_error\", \"provider_stream_stopped\", + \"agent_session_connect_failed\", \"media_stream_ended\", \"bridge_cancelled\", + \"bridge_failed\", \"managed_hangup\", \"managed_transfer\", \"manage_hangup_failed\", and + \"manage_transfer_failed\".""" + provider_status_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider status code associated with the terminal result.""" + provider_sub_code: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider subcode associated with the terminal result.""" + provider_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The provider message associated with the terminal result.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + provider: Union[str, "_models.TelephonyProvider"], + status: Union[str, "_models.TelephonyCallStatus"], + phase: Union[str, "_models.TelephonyCallPhase"], + started_at: datetime.datetime, + provider_call_id: Optional[str] = None, + caller_number: Optional[str] = None, + provider_number: Optional[str] = None, + answered_at: Optional[datetime.datetime] = None, + media_connected_at: Optional[datetime.datetime] = None, + agent_session_ready_at: Optional[datetime.datetime] = None, + ended_at: Optional[datetime.datetime] = None, + duration_ms: Optional[datetime.timedelta] = None, + end_reason: Optional[Union[str, "_models.TelephonyCallEndReason"]] = None, + provider_status_code: Optional[int] = None, + provider_sub_code: Optional[int] = None, + provider_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 TelephonyCallTiming(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Detailed provider-neutral timing for an inbound telephony call. + + :ivar received_at: The Unix timestamp (in seconds) for when the provider webhook was received. + :vartype received_at: ~datetime.datetime + :ivar validated_at: The Unix timestamp (in seconds) for when webhook validation completed. + :vartype validated_at: ~datetime.datetime + :ivar admitted_at: The Unix timestamp (in seconds) for when the call was admitted to an agent + binding. + :vartype admitted_at: ~datetime.datetime + :ivar answer_requested_at: The Unix timestamp (in seconds) for when the service requested that + the provider answer the call. + :vartype answer_requested_at: ~datetime.datetime + :ivar answered_at: The Unix timestamp (in seconds) for when the provider reported that the call + was answered. + :vartype answered_at: ~datetime.datetime + :ivar media_connected_at: The Unix timestamp (in seconds) for when the provider media channel + connected. + :vartype media_connected_at: ~datetime.datetime + :ivar agent_session_ready_at: The Unix timestamp (in seconds) for when the voice-agent session + became ready. + :vartype agent_session_ready_at: ~datetime.datetime + :ivar first_caller_audio_at: The Unix timestamp (in seconds) for when caller audio was first + observed. + :vartype first_caller_audio_at: ~datetime.datetime + :ivar first_agent_audio_at: The Unix timestamp (in seconds) for when agent audio was first + observed. + :vartype first_agent_audio_at: ~datetime.datetime + :ivar ended_at: The Unix timestamp (in seconds) for when the call reached a terminal state. + :vartype ended_at: ~datetime.datetime + :ivar duration_basis: The timestamp used as the basis for duration. Known values are: + "answered" and "received". + :vartype duration_basis: str or ~azure.ai.projects.models.TelephonyCallDurationBasis + :ivar timestamp_source: The primary source of the timing milestones. Individual lifecycle + events identify their own timestamp source separately. Required. Known values are: "provider", + "gateway", and "derived". + :vartype timestamp_source: str or ~azure.ai.projects.models.TelephonyCallTimestampSource + """ + + received_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider webhook was received.""" + validated_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when webhook validation completed.""" + admitted_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the call was admitted to an agent binding.""" + answer_requested_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the service requested that the provider answer the + call.""" + answered_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider reported that the call was answered.""" + media_connected_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the provider media channel connected.""" + agent_session_ready_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the voice-agent session became ready.""" + first_caller_audio_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when caller audio was first observed.""" + first_agent_audio_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when agent audio was first observed.""" + ended_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the call reached a terminal state.""" + duration_basis: Optional[Union[str, "_models.TelephonyCallDurationBasis"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The timestamp used as the basis for duration. Known values are: \"answered\" and \"received\".""" + timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The primary source of the timing milestones. Individual lifecycle events identify their own + timestamp source separately. Required. Known values are: \"provider\", \"gateway\", and + \"derived\".""" + + @overload + def __init__( + self, + *, + timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"], + received_at: Optional[datetime.datetime] = None, + validated_at: Optional[datetime.datetime] = None, + admitted_at: Optional[datetime.datetime] = None, + answer_requested_at: Optional[datetime.datetime] = None, + answered_at: Optional[datetime.datetime] = None, + media_connected_at: Optional[datetime.datetime] = None, + agent_session_ready_at: Optional[datetime.datetime] = None, + first_caller_audio_at: Optional[datetime.datetime] = None, + first_agent_audio_at: Optional[datetime.datetime] = None, + ended_at: Optional[datetime.datetime] = None, + duration_basis: Optional[Union[str, "_models.TelephonyCallDurationBasis"]] = 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 TelephonyCallTrace(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Correlation from a durable telephony call record to its customer-facing Foundry trace. + + :ivar status: The trace availability status. Required. Known values are: "pending", "emitting", + "available", "not_recorded", "not_applicable", and "failed". + :vartype status: str or ~azure.ai.projects.models.TelephonyCallTraceStatus + :ivar trace_id: The W3C trace identifier, when a trace was recorded. + :vartype trace_id: str + :ivar root_span_id: The root span identifier, when a trace was recorded. + :vartype root_span_id: str + :ivar conversation_id: The voice-agent conversation identifier, when a conversation was + created. + :vartype conversation_id: str + :ivar mode: Whether the trace was emitted live or after the call ended. Known values are: + "live" and "post_call". + :vartype mode: str or ~azure.ai.projects.models.TelephonyCallTraceMode + """ + + status: Union[str, "_models.TelephonyCallTraceStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The trace availability status. Required. Known values are: \"pending\", \"emitting\", + \"available\", \"not_recorded\", \"not_applicable\", and \"failed\".""" + trace_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The W3C trace identifier, when a trace was recorded.""" + root_span_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The root span identifier, when a trace was recorded.""" + conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice-agent conversation identifier, when a conversation was created.""" + mode: Optional[Union[str, "_models.TelephonyCallTraceMode"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Whether the trace was emitted live or after the call ended. Known values are: \"live\" and + \"post_call\".""" + + @overload + def __init__( + self, + *, + status: Union[str, "_models.TelephonyCallTraceStatus"], + trace_id: Optional[str] = None, + root_span_id: Optional[str] = None, + conversation_id: Optional[str] = None, + mode: Optional[Union[str, "_models.TelephonyCallTraceMode"]] = 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 TelephonyCampaign(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Agent-owned outbound call Campaign. Creation/replacement authorizes execution after successful + preparation. + + :ivar connection_name: Human-readable name of the provider connection in the current project. + Required. + :vartype connection_name: str + :ivar source: Typed caller address shared with generated CallJobs. The connection validates + source support separately from recipient support. Required. + :vartype source: ~azure.ai.projects.models.TelephonyAddress + :ivar recipients: 1-100 recipients, exclusive with recipient_dataset. The whole UTF-8 request + is limited to 1 MiB. Omitted from reads; retain the submission for row correlation. + :vartype recipients: list[~azure.ai.projects.models.TelephonyRecipient] + :ivar recipient_dataset: Same-project CSV/JSON/JSONL uri_file, exclusive with recipients. + Omitted version pins latest per preparation. Limits: 1-1,000,000 rows, 256 MiB decoded/file, 1 + MiB/row. + :vartype recipient_dataset: ~azure.ai.projects.models.TelephonyCampaignDatasetReference + :ivar schedule: Dispatch schedule; omission equals ImmediateSchedule. Every mode waits for + successful preparation, then follows its schedule and available capacity. + :vartype schedule: ~azure.ai.projects.models.TelephonyCampaignSchedule + :ivar retry_policy: Per-recipient retries. Omit for one attempt; generated CallJobs return + fixed_interval with max_attempts=1 and interval=0 seconds. + :vartype retry_policy: ~azure.ai.projects.models.TelephonyOutboundRetryPolicy + :ivar status: Business execution state. Each asynchronous action has its own retained operation + monitor. Required. Known values are: "validating", "running", "cancelling", "completed", + "failed", "cancelled", and "deleting". + :vartype status: str or ~azure.ai.projects.models.TelephonyCampaignStatus + :ivar error: Preparation/control failure, cleared on retry. Never includes secrets or raw + recipient values. + :vartype error: ~azure.ai.projects.models.ApiError + :ivar name: Immutable name supplied as campaign_name in the PUT path, not the request body; + echoed in responses. Unique within the project and Agent. Required. + :vartype name: str + :ivar created_at: Creation time. Required. + :vartype created_at: ~datetime.datetime + :ivar updated_at: Last observable progress update. Required. + :vartype updated_at: ~datetime.datetime + :ivar etag: Conditional-action token, not a cache validator. Changes with control state, not + progress. Required. + :vartype etag: str + :ivar operation_id: Latest accepted action, for discovery only. Poll the initiating response's + Operation-Id/Operation-Location instead. Required. + :vartype operation_id: str + :ivar finished_at: Time of terminal completion for the current round; cleared when failed + preparation is replaced. + :vartype finished_at: ~datetime.datetime + :ivar locked_agent_version: Latest Agent version pinned once per preparation and shared by + retries/calls. Omitted until resolved; replacement clears it. Unavailable pins fail without + fallback. + :vartype locked_agent_version: str + :ivar progress: Available partial accounting even when the job fails or is cancelled. Required. + :vartype progress: ~azure.ai.projects.models.TelephonyCampaignProgress + """ + + connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Human-readable name of the provider connection in the current project. Required.""" + source: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Typed caller address shared with generated CallJobs. The connection validates source support + separately from recipient support. Required.""" + recipients: Optional[list["_models.TelephonyRecipient"]] = rest_field(visibility=["create"]) + """1-100 recipients, exclusive with recipient_dataset. The whole UTF-8 request is limited to 1 + MiB. Omitted from reads; retain the submission for row correlation.""" + recipient_dataset: Optional["_models.TelephonyCampaignDatasetReference"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Same-project CSV/JSON/JSONL uri_file, exclusive with recipients. Omitted version pins latest + per preparation. Limits: 1-1,000,000 rows, 256 MiB decoded/file, 1 MiB/row.""" + schedule: Optional["_models.TelephonyCampaignSchedule"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Dispatch schedule; omission equals ImmediateSchedule. Every mode waits for successful + preparation, then follows its schedule and available capacity.""" + retry_policy: Optional["_models.TelephonyOutboundRetryPolicy"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Per-recipient retries. Omit for one attempt; generated CallJobs return fixed_interval with + max_attempts=1 and interval=0 seconds.""" + status: Union[str, "_models.TelephonyCampaignStatus"] = rest_field(visibility=["read"]) + """Business execution state. Each asynchronous action has its own retained operation monitor. + Required. Known values are: \"validating\", \"running\", \"cancelling\", \"completed\", + \"failed\", \"cancelled\", and \"deleting\".""" + error: Optional["_models.ApiError"] = rest_field(visibility=["read"]) + """Preparation/control failure, cleared on retry. Never includes secrets or raw recipient values.""" + name: str = rest_field(visibility=["read"]) + """Immutable name supplied as campaign_name in the PUT path, not the request body; echoed in + responses. Unique within the project and Agent. Required.""" + created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """Creation time. Required.""" + updated_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """Last observable progress update. Required.""" + etag: str = rest_field(visibility=["read"]) + """Conditional-action token, not a cache validator. Changes with control state, not progress. + Required.""" + operation_id: str = rest_field(visibility=["read"]) + """Latest accepted action, for discovery only. Poll the initiating response's + Operation-Id/Operation-Location instead. Required.""" + finished_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """Time of terminal completion for the current round; cleared when failed preparation is replaced.""" + locked_agent_version: Optional[str] = rest_field(visibility=["read"]) + """Latest Agent version pinned once per preparation and shared by retries/calls. Omitted until + resolved; replacement clears it. Unavailable pins fail without fallback.""" + progress: "_models.TelephonyCampaignProgress" = rest_field(visibility=["read"]) + """Available partial accounting even when the job fails or is cancelled. Required.""" + + @overload + def __init__( + self, + *, + connection_name: str, + source: "_models.TelephonyAddress", + recipients: Optional[list["_models.TelephonyRecipient"]] = None, + recipient_dataset: Optional["_models.TelephonyCampaignDatasetReference"] = None, + schedule: Optional["_models.TelephonyCampaignSchedule"] = None, + retry_policy: Optional["_models.TelephonyOutboundRetryPolicy"] = 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 TelephonyCampaignDatasetReference(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Reference to a Foundry Dataset in the current project. Consuming operations define supported + Dataset kinds and resolution behavior. + + :ivar name: Dataset name. Required. + :vartype name: str + :ivar version: Optional Dataset version. Omit to select latest when the consuming operation + resolves the reference. + :vartype version: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Dataset name. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional Dataset version. Omit to select latest when the consuming operation resolves the + reference.""" + + @overload + def __init__( + self, + *, + name: str, + version: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class TelephonyCampaignOperation(_Model): + """Preparation/cancel/delete monitor bound to its original Campaign instance/round, independent of + later actions. Omits result. Retained for the Campaign lifetime and at least 24 hours after + both completion and deletion. + + :ivar id: Server-assigned unique identifier. Required. + :vartype id: str + :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 kind: Work tracked by this monitor. Required. Known values are: "validation", "cancel", + and "delete". + :vartype kind: str or ~azure.ai.projects.models.TelephonyCampaignOperationKind + :ivar created_at: Creation time of this operation. Required. + :vartype created_at: ~datetime.datetime + :ivar finished_at: When preparation, cancellation or deletion finished. + :vartype finished_at: ~datetime.datetime + """ + + id: str = rest_field(visibility=["read"]) + """Server-assigned unique identifier. Required.""" + 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.""" + kind: Union[str, "_models.TelephonyCampaignOperationKind"] = rest_field(visibility=["read"]) + """Work tracked by this monitor. Required. Known values are: \"validation\", \"cancel\", and + \"delete\".""" + created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """Creation time of this operation. Required.""" + finished_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """When preparation, cancellation or deletion finished.""" + + +class TelephonyCampaignProgress(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Recipient execution counts, zero until preparation succeeds; then mutually exclusive and + summing to total_recipients. + + :ivar total_recipients: Total input rows, including invalid rows. Omitted until known; never an + estimate. + :vartype total_recipients: int + :ivar pending: Recipients waiting for their schedule, capacity or retry after preparation has + completed. Required. + :vartype pending: int + :ivar active: Recipients with a durable origination reservation or unresolved provider attempt, + including dispatching before a call ID is received. Required. + :vartype active: int + :ivar completed: Recipients whose CallJob completed; not proof of business success. Required. + :vartype completed: int + :ivar failed: Recipients whose CallJob exhausted retries or failed. Required. + :vartype failed: int + :ivar cancelled: Recipients cancelled before completion. Does not include dispatch-window + expiry. Required. + :vartype cancelled: int + :ivar expired: Recipients whose dispatch deadline elapsed before a new attempt could start. + Required. + :vartype expired: int + """ + + total_recipients: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total input rows, including invalid rows. Omitted until known; never an estimate.""" + pending: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipients waiting for their schedule, capacity or retry after preparation has completed. + Required.""" + active: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipients with a durable origination reservation or unresolved provider attempt, including + dispatching before a call ID is received. Required.""" + completed: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipients whose CallJob completed; not proof of business success. Required.""" + failed: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipients whose CallJob exhausted retries or failed. Required.""" + cancelled: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipients cancelled before completion. Does not include dispatch-window expiry. Required.""" + expired: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipients whose dispatch deadline elapsed before a new attempt could start. Required.""" + + @overload + def __init__( + self, + *, + pending: int, + active: int, + completed: int, + failed: int, + cancelled: int, + expired: int, + total_recipients: 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 TelephonyCampaignValidationError(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Invalid-row diagnostic for current preparation; execution errors are in CallJobs. + + :ivar row_number: One-based source row or inline item position. Required. + :vartype row_number: int + :ivar error: Row validation error; param identifies the field. Never includes raw values or + secrets. Required. + :vartype error: ~azure.ai.projects.models.ApiError + """ + + row_number: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """One-based source row or inline item position. Required.""" + error: "_models.ApiError" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Row validation error; param identifies the field. Never includes raw values or secrets. + Required.""" + + @overload + def __init__( + self, + *, + row_number: int, + error: "_models.ApiError", + ) -> 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 TelephonyRecipient(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """One recipient in an inline campaign input. Each input position is a separate intended call, + including repeated destinations. + + :ivar destination: Recipient address; currently phone_number only. Unsupported types fail + preparation; future variants can reuse this field. Required. + :vartype destination: ~azure.ai.projects.models.TelephonyAddress + :ivar structured_inputs: Agent inputs with nested JSON/null, unique names and depth at most 16. + Agent schemas/defaults apply. Replay preserves types, exact numbers, array order and + null/omission, but ignores object order; use lossless numeric serialization. + :vartype structured_inputs: dict[str, any] + :ivar scheduled_at: Earliest dispatch time for recipient scheduling. Required only when + schedule.type is recipient; forbidden for other modes. + :vartype scheduled_at: ~datetime.datetime + """ + + destination: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Recipient address; currently phone_number only. Unsupported types fail preparation; future + variants can reuse this field. Required.""" + structured_inputs: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Agent inputs with nested JSON/null, unique names and depth at most 16. Agent schemas/defaults + apply. Replay preserves types, exact numbers, array order and null/omission, but ignores object + order; use lossless numeric serialization.""" + scheduled_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """Earliest dispatch time for recipient scheduling. Required only when schedule.type is recipient; + forbidden for other modes.""" + + @overload + def __init__( + self, + *, + destination: "_models.TelephonyAddress", + structured_inputs: Optional[dict[str, Any]] = None, + scheduled_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 TelephonyTransferTarget(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A named destination to which the voice agent may transfer a call. + + :ivar name: The unique name exposed to the voice agent for this transfer target. Required. + :vartype name: str + :ivar description: A description that helps the voice agent decide when to use this target. + Required. + :vartype description: str + :ivar destination: The shared typed address to transfer to. The selected provider validates + supported destination types. Required. + :vartype destination: ~azure.ai.projects.models.TelephonyAddress + """ + + name: str = rest_field(visibility=["read", "create"]) + """The unique name exposed to the voice agent for this transfer target. Required.""" + description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description that helps the voice agent decide when to use this target. Required.""" + destination: "_models.TelephonyAddress" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The shared typed address to transfer to. The selected provider validates supported destination + types. Required.""" + + @overload + def __init__( + self, + *, + name: str, + description: str, + destination: "_models.TelephonyAddress", + ) -> 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 TelephonyTransferTargets(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The telephony transfer targets configured for one voice agent. + + :ivar transfer_targets: The complete set of destinations to which the voice agent may transfer + calls. An empty array clears all targets when replacing the configuration. Required. + :vartype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + """ + + transfer_targets: list["_models.TelephonyTransferTarget"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The complete set of destinations to which the voice agent may transfer calls. An empty array + clears all targets when replacing the configuration. Required.""" + + @overload + def __init__( + self, + *, + transfer_targets: list["_models.TelephonyTransferTarget"], + ) -> 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 TextResponseFormat(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An object specifying the format that the model must output. Configuring ``{ "type": + "json_schema" }`` enables Structured Outputs, which ensures the model will match your supplied + JSON schema. Learn more in the `Structured Outputs guide + `_. The default format is ``{ + "type": "text" }`` with no additional options. *Not recommended for gpt-4o and newer models:** + Setting to ``{ "type": "json_object" }`` enables the older JSON mode, which ensures the message + the model generates is valid JSON. Using ``json_schema`` is preferred for models that support + it. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + TextResponseFormatJsonObject, TextResponseFormatJsonSchema, TextResponseFormatText + + :ivar type: Required. Known values are: "text", "json_schema", and "json_object". + :vartype type: str or ~azure.ai.projects.models.TextResponseFormatConfigurationType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Required. Known values are: \"text\", \"json_schema\", and \"json_object\".""" + + @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 TextResponseFormatJsonObject(TextResponseFormat, discriminator="json_object"): + """JSON object. + + :ivar type: The type of response format being defined. Always ``json_object``. Required. + JSON_OBJECT. + :vartype type: str or ~azure.ai.projects.models.JSON_OBJECT + """ + + type: Literal[TextResponseFormatConfigurationType.JSON_OBJECT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of response format being defined. Always ``json_object``. Required. JSON_OBJECT.""" + + @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 = TextResponseFormatConfigurationType.JSON_OBJECT # type: ignore + + +class TextResponseFormatJsonSchema( + TextResponseFormat, discriminator="json_schema" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """JSON schema. + + :ivar type: The type of response format being defined. Always ``json_schema``. Required. + JSON_SCHEMA. + :vartype type: str or ~azure.ai.projects.models.JSON_SCHEMA + :ivar description: A description of what the response format is for, used by the model to + determine how to respond in the format. + :vartype description: str + :ivar name: The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and + dashes, with a maximum length of 64. Required. + :vartype name: str + :ivar schema: Required. + :vartype schema: dict[str, any] + :ivar strict: + :vartype strict: bool + """ + + type: Literal[TextResponseFormatConfigurationType.JSON_SCHEMA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of response format being defined. Always ``json_schema``. Required. JSON_SCHEMA.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description of what the response format is for, used by the model to determine how to respond + in the format.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with + a maximum length of 64. Required.""" + schema: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + strict: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + name: str, + schema: dict[str, Any], + description: Optional[str] = None, + strict: 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) + self.type = TextResponseFormatConfigurationType.JSON_SCHEMA # type: ignore + + +class TextResponseFormatText(TextResponseFormat, discriminator="text"): + """Text. + + :ivar type: The type of response format being defined. Always ``text``. Required. TEXT. + :vartype type: str or ~azure.ai.projects.models.TEXT + """ + + type: Literal[TextResponseFormatConfigurationType.TEXT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of response format being defined. Always ``text``. Required. TEXT.""" + + @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 = TextResponseFormatConfigurationType.TEXT # type: ignore + + +class TimerRoutineTrigger( + RoutineTrigger, discriminator="timer" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """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: The UTC date and time at which the timer fires. + :vartype at: ~datetime.datetime + """ + + 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: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The UTC date and time at which the timer fires.""" + + @overload + def __init__( + self, + *, + 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) + self.type = RoutineTriggerType.TIMER # type: ignore + + +class ToolboxObject(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A toolbox that stores reusable tool definitions for agents. + + :ivar id: The unique identifier of the toolbox. Required. + :vartype id: str + :ivar name: The name of the toolbox. Required. + :vartype name: str + :ivar updated_at: The Unix timestamp (seconds) when the toolbox was last updated. This value + changes when a new toolbox version is created or the toolbox is updated. Required. + :vartype updated_at: ~datetime.datetime + :ivar versions: The versions associated with the toolbox. Required. + :vartype versions: ~azure.ai.projects.models.ToolboxVersions + :ivar default_version: The version identifier that the toolbox currently points to. Defaults to + the latest version. Can be changed via updateToolbox. Required. + :vartype default_version: str + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of the toolbox. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the toolbox. Required.""" + updated_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (seconds) when the toolbox was last updated. This value changes when a new + toolbox version is created or the toolbox is updated. Required.""" + versions: "_models.ToolboxVersions" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The versions associated with the toolbox. Required.""" + default_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version identifier that the toolbox currently points to. Defaults to the latest version. + Can be changed via updateToolbox. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + name: str, + updated_at: datetime.datetime, + versions: "_models.ToolboxVersions", + default_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 ToolboxPolicies(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Policy configuration for a toolbox, including content safety and other governance settings. + + :ivar rai_config: Responsible AI content filtering configuration. + :vartype rai_config: ~azure.ai.projects.models.RaiConfig + """ + + rai_config: Optional["_models.RaiConfig"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Responsible AI content filtering configuration.""" + + @overload + def __init__( + self, + *, + rai_config: Optional["_models.RaiConfig"] = 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 ToolboxSearchPreviewToolboxTool( + ToolboxTool, discriminator="toolbox_search_preview" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A toolbox search tool stored in a toolbox. + + :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 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 + """ + + type: Literal[ToolboxToolType.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.""" + + @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 = ToolboxToolType.TOOLBOX_SEARCH_PREVIEW # type: ignore + + +class ToolboxShellEnvironment(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An execution environment for a shell tool stored in a toolbox. This environment model is scoped + to toolbox configuration and does not modify the OpenAI shell environment contract. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + ToolboxShellContainerAutoEnvironment, ToolboxShellContainerReferenceEnvironment + + :ivar type: The type of the shell execution environment. Required. Default value is None. + :vartype type: str + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of the shell execution environment. Required. Default value is None.""" + + @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 ToolboxShellContainerAutoEnvironment( + ToolboxShellEnvironment, discriminator="container_auto" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An automatically provisioned container environment for a shell tool stored in a toolbox. + + :ivar type: The type of the shell execution environment. Always ``container_auto``. Required. + Default value is "container_auto". + :vartype type: str + :ivar file_ids: An optional list of uploaded files to make available to your code. + :vartype file_ids: list[str] + :ivar memory_limit: Known values are: "1g", "4g", "16g", and "64g". + :vartype memory_limit: str or ~azure.ai.projects.models.ContainerMemoryLimit + :ivar skills: An optional list of skills referenced by id or inline data. + :vartype skills: list[~azure.ai.projects.models.ContainerSkill] + :ivar network_policy: The network access policy for the container. When omitted, the service + defaults to disabled outbound network access. + :vartype network_policy: ~azure.ai.projects.models.ToolboxShellNetworkPolicy + """ + + type: Literal["container_auto"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the shell execution environment. Always ``container_auto``. Required. Default value + is \"container_auto\".""" + file_ids: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional list of uploaded files to make available to your code.""" + memory_limit: Optional[Union[str, "_models.ContainerMemoryLimit"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Known values are: \"1g\", \"4g\", \"16g\", and \"64g\".""" + skills: Optional[list["_models.ContainerSkill"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """An optional list of skills referenced by id or inline data.""" + network_policy: Optional["_models.ToolboxShellNetworkPolicy"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The network access policy for the container. When omitted, the service defaults to disabled + outbound network access.""" + + @overload + def __init__( + self, + *, + file_ids: Optional[list[str]] = None, + memory_limit: Optional[Union[str, "_models.ContainerMemoryLimit"]] = None, + skills: Optional[list["_models.ContainerSkill"]] = None, + network_policy: Optional["_models.ToolboxShellNetworkPolicy"] = 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 = "container_auto" # type: ignore + + +class ToolboxShellContainerReferenceEnvironment( + ToolboxShellEnvironment, discriminator="container_reference" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """An existing container environment for a shell tool stored in a toolbox. + + :ivar type: The type of the shell execution environment. Always ``container_reference``. + Required. Default value is "container_reference". + :vartype type: str + :ivar container_id: The ID of the referenced container. Required. + :vartype container_id: str + """ + + type: Literal["container_reference"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the shell execution environment. Always ``container_reference``. Required. Default + value is \"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 = "container_reference" # type: ignore + + +class ToolboxShellNetworkPolicy(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Network access policy for an automatically provisioned toolbox shell container. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + ToolboxShellNetworkPolicyDisabled + + :ivar type: The type of network access policy. Required. Default value is None. + :vartype type: str + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of network access policy. Required. Default value is None.""" + + @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 ToolboxShellNetworkPolicyDisabled(ToolboxShellNetworkPolicy, discriminator="disabled"): + """A network policy that disables outbound access from a toolbox shell container. + + :ivar type: The type of network access policy. Always ``disabled``. Required. Default value is + "disabled". + :vartype type: str + """ + + type: Literal["disabled"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of network access policy. Always ``disabled``. Required. Default value is + \"disabled\".""" + + @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 = "disabled" # type: ignore + + +class ToolboxSkill(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A skill source included in a toolbox. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + ToolboxSkillReference + + :ivar type: The type of skill source. Required. Default value is None. + :vartype type: str + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of skill source. Required. Default value is None.""" + + @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 ToolboxSkillReference( + ToolboxSkill, discriminator="skill_reference" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A reference to an existing skill to include in a toolbox. + + :ivar type: The type of skill source. Required. Default value is "skill_reference". + :vartype type: str + :ivar name: The name of the skill. Required. + :vartype name: str + :ivar version: The version of the skill. If not specified, the skill's default version is used. + When a version is specified, the reference is pinned to that immutable version. + :vartype version: str + """ + + type: Literal["skill_reference"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of skill source. Required. Default value is \"skill_reference\".""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the skill. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version of the skill. If not specified, the skill's default version is used. When a version + is specified, the reference is pinned to that immutable version.""" + + @overload + def __init__( + self, + *, + name: str, + 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 = "skill_reference" # type: ignore + + +class ToolboxVersionObject(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A specific version of a toolbox. + + :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. Required. + :vartype metadata: dict[str, str] + :ivar id: The unique identifier of the toolbox version. Required. + :vartype id: str + :ivar name: The name of the toolbox. Required. + :vartype name: str + :ivar version: The version identifier of the toolbox. Toolbox versions are immutable and every + update creates a new version. Required. + :vartype version: str + :ivar description: A human-readable description of the toolbox. + :vartype description: str + :ivar created_at: The Unix timestamp (seconds) when the toolbox version was created. Required. + :vartype created_at: ~datetime.datetime + :ivar tools: The list of tools contained in this toolbox version. Required. + :vartype tools: list[~azure.ai.projects.models.ToolboxTool] + :ivar skills: The list of skill sources included in this toolbox version. + :vartype skills: list[~azure.ai.projects.models.ToolboxSkill] + :ivar policies: Policy configuration for the toolbox version. + :vartype policies: ~azure.ai.projects.models.ToolboxPolicies + """ + + metadata: 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. Required.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of the toolbox version. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the toolbox. Required.""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version identifier of the toolbox. Toolbox versions are immutable and every update creates + a new version. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the toolbox.""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (seconds) when the toolbox version was created. Required.""" + tools: list["_models.ToolboxTool"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The list of tools contained in this toolbox version. Required.""" + skills: Optional[list["_models.ToolboxSkill"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The list of skill sources included in this toolbox version.""" + policies: Optional["_models.ToolboxPolicies"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Policy configuration for the toolbox version.""" + + @overload + def __init__( + self, + *, + metadata: dict[str, str], + id: str, # pylint: disable=redefined-builtin + name: str, + version: str, + created_at: datetime.datetime, + tools: list["_models.ToolboxTool"], + description: Optional[str] = None, + skills: Optional[list["_models.ToolboxSkill"]] = None, + policies: Optional["_models.ToolboxPolicies"] = 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 ToolboxVersions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The versions associated with a toolbox. + + :ivar latest: The latest version of the toolbox. Required. + :vartype latest: ~azure.ai.projects.models.ToolboxVersionObject + """ + + latest: "_models.ToolboxVersionObject" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The latest version of the toolbox. Required.""" + + @overload + def __init__( + self, + *, + latest: "_models.ToolboxVersionObject", + ) -> 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 ToolChoiceAllowed( + ToolChoiceParam, discriminator="allowed_tools" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Allowed tools. + + :ivar type: Allowed tool configuration type. Always ``allowed_tools``. Required. ALLOWED_TOOLS. + :vartype type: str or ~azure.ai.projects.models.ALLOWED_TOOLS + :ivar mode: Constrains the tools available to the model to a pre-defined set. ``auto`` allows + the model to pick from among the allowed tools and generate a message. ``required`` requires + the model to call one or more of the allowed tools. Required. Is either a Literal["auto"] type + or a Literal["required"] type. + :vartype mode: str or str + :ivar tools: Required. A list of tool definitions that the model should be allowed to call. For + the Responses API, the list of tool definitions might look like: + + .. code-block:: json + + [ + { "type": "function", "name": "get_weather" }, + { "type": "mcp", "server_label": "deepwiki" }, + { "type": "image_generation" } + ] + :vartype tools: list[dict[str, any]] + """ + + type: Literal[ToolChoiceParamType.ALLOWED_TOOLS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Allowed tool configuration type. Always ``allowed_tools``. Required. ALLOWED_TOOLS.""" + mode: Literal["auto", "required"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Constrains the tools available to the model to a pre-defined set. ``auto`` allows the model to + pick from among the allowed tools and generate a message. ``required`` requires the model to + call one or more of the allowed tools. Required. Is either a Literal[\"auto\"] type or a + Literal[\"required\"] type.""" + tools: list[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. A list of tool definitions that the model should be allowed to call. For the + Responses API, the list of tool definitions might look like: + + .. code-block:: json + + [ + { \"type\": \"function\", \"name\": \"get_weather\" }, + { \"type\": \"mcp\", \"server_label\": \"deepwiki\" }, + { \"type\": \"image_generation\" } + ]""" + + @overload + def __init__( + self, + *, + mode: Literal["auto", "required"], + tools: list[dict[str, Any]], + ) -> 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 = ToolChoiceParamType.ALLOWED_TOOLS # type: ignore + + +class ToolChoiceCodeInterpreter(ToolChoiceParam, discriminator="code_interpreter"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. CODE_INTERPRETER. + :vartype type: str or ~azure.ai.projects.models.CODE_INTERPRETER + """ + + type: Literal[ToolChoiceParamType.CODE_INTERPRETER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. CODE_INTERPRETER.""" + + @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 = ToolChoiceParamType.CODE_INTERPRETER # type: ignore + + +class ToolChoiceComputer(ToolChoiceParam, discriminator="computer"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. COMPUTER. + :vartype type: str or ~azure.ai.projects.models.COMPUTER + """ + + type: Literal[ToolChoiceParamType.COMPUTER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. COMPUTER.""" + + @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 = ToolChoiceParamType.COMPUTER # type: ignore + + +class ToolChoiceComputerUse(ToolChoiceParam, discriminator="computer_use"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. COMPUTER_USE. + :vartype type: str or ~azure.ai.projects.models.COMPUTER_USE + """ + + type: Literal[ToolChoiceParamType.COMPUTER_USE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. COMPUTER_USE.""" + + @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 = ToolChoiceParamType.COMPUTER_USE # type: ignore + + +class ToolChoiceComputerUsePreview(ToolChoiceParam, discriminator="computer_use_preview"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. COMPUTER_USE_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.COMPUTER_USE_PREVIEW + """ + + type: Literal[ToolChoiceParamType.COMPUTER_USE_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. COMPUTER_USE_PREVIEW.""" + + @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 = ToolChoiceParamType.COMPUTER_USE_PREVIEW # type: ignore + + +class ToolChoiceCustom( + ToolChoiceParam, discriminator="custom" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Custom tool. + + :ivar type: For custom tool calling, the type is always ``custom``. Required. CUSTOM. + :vartype type: str or ~azure.ai.projects.models.CUSTOM + :ivar name: The name of the custom tool to call. Required. + :vartype name: str + """ + + type: Literal[ToolChoiceParamType.CUSTOM] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """For custom tool calling, the type is always ``custom``. Required. CUSTOM.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the custom tool to call. Required.""" + + @overload + def __init__( + self, + *, + 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) + self.type = ToolChoiceParamType.CUSTOM # type: ignore + + +class ToolChoiceFileSearch(ToolChoiceParam, discriminator="file_search"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. FILE_SEARCH. + :vartype type: str or ~azure.ai.projects.models.FILE_SEARCH + """ + + type: Literal[ToolChoiceParamType.FILE_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. FILE_SEARCH.""" + + @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 = ToolChoiceParamType.FILE_SEARCH # type: ignore + + +class ToolChoiceFunction( + ToolChoiceParam, discriminator="function" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Function tool. + + :ivar type: For function calling, the type is 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 + """ + + type: Literal[ToolChoiceParamType.FUNCTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """For function calling, the type is always ``function``. Required. FUNCTION.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the function to call. Required.""" + + @overload + def __init__( + self, + *, + 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) + self.type = ToolChoiceParamType.FUNCTION # type: ignore + + +class ToolChoiceImageGeneration(ToolChoiceParam, discriminator="image_generation"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. IMAGE_GENERATION. + :vartype type: str or ~azure.ai.projects.models.IMAGE_GENERATION + """ + + type: Literal[ToolChoiceParamType.IMAGE_GENERATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. IMAGE_GENERATION.""" + + @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 = ToolChoiceParamType.IMAGE_GENERATION # type: ignore + + +class ToolChoiceMCP( + ToolChoiceParam, discriminator="mcp" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """MCP tool. + + :ivar type: For MCP tools, the type is always ``mcp``. Required. MCP. + :vartype type: str or ~azure.ai.projects.models.MCP + :ivar server_label: The label of the MCP server to use. Required. + :vartype server_label: str + :ivar name: + :vartype name: str + """ + + type: Literal[ToolChoiceParamType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """For MCP tools, the type is always ``mcp``. Required. MCP.""" + server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The label of the MCP server to use. Required.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + + @overload + def __init__( + self, + *, + server_label: str, + name: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = ToolChoiceParamType.MCP # type: ignore + + +class ToolChoiceWebSearchPreview(ToolChoiceParam, discriminator="web_search_preview"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. WEB_SEARCH_PREVIEW. + :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW + """ + + type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. WEB_SEARCH_PREVIEW.""" + + @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 = ToolChoiceParamType.WEB_SEARCH_PREVIEW # type: ignore + + +class ToolChoiceWebSearchPreview20250311(ToolChoiceParam, discriminator="web_search_preview_2025_03_11"): + """Indicates that the model should use a built-in tool to generate a response. `Learn more about + built-in tools `_. + + :ivar type: Required. WEB_SEARCH_PREVIEW_2025_03_11. + :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW_2025_03_11 + """ + + type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. WEB_SEARCH_PREVIEW_2025_03_11.""" @overload def __init__( self, - *, - timestamp_source: Union[str, "_models.TelephonyCallTimestampSource"], - received_at: Optional[datetime.datetime] = None, - validated_at: Optional[datetime.datetime] = None, - admitted_at: Optional[datetime.datetime] = None, - answer_requested_at: Optional[datetime.datetime] = None, - answered_at: Optional[datetime.datetime] = None, - media_connected_at: Optional[datetime.datetime] = None, - agent_session_ready_at: Optional[datetime.datetime] = None, - first_caller_audio_at: Optional[datetime.datetime] = None, - first_agent_audio_at: Optional[datetime.datetime] = None, - ended_at: Optional[datetime.datetime] = None, - duration_basis: Optional[Union[str, "_models.TelephonyCallDurationBasis"]] = None, ) -> None: ... @overload @@ -25148,52 +34224,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11 # type: ignore -class TelephonyCallTrace(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Correlation from a durable telephony call record to its customer-facing Foundry trace. +class ToolConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Per-tool configuration that controls tool visibility and search behavior. - :ivar status: The trace availability status. Required. Known values are: "pending", "emitting", - "available", "not_recorded", "not_applicable", and "failed". - :vartype status: str or ~azure.ai.projects.models.TelephonyCallTraceStatus - :ivar trace_id: The W3C trace identifier, when a trace was recorded. - :vartype trace_id: str - :ivar root_span_id: The root span identifier, when a trace was recorded. - :vartype root_span_id: str - :ivar conversation_id: The voice-agent conversation identifier, when a conversation was - created. - :vartype conversation_id: str - :ivar mode: Whether the trace was emitted live or after the call ended. Known values are: - "live" and "post_call". - :vartype mode: str or ~azure.ai.projects.models.TelephonyCallTraceMode + :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 """ - status: Union[str, "_models.TelephonyCallTraceStatus"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The trace availability status. Required. Known values are: \"pending\", \"emitting\", - \"available\", \"not_recorded\", \"not_applicable\", and \"failed\".""" - trace_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The W3C trace identifier, when a trace was recorded.""" - root_span_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The root span identifier, when a trace was recorded.""" - conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice-agent conversation identifier, when a conversation was created.""" - mode: Optional[Union[str, "_models.TelephonyCallTraceMode"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Whether the trace was emitted live or after the call ended. Known values are: \"live\" and - \"post_call\".""" + 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, *, - status: Union[str, "_models.TelephonyCallTraceStatus"], - trace_id: Optional[str] = None, - root_span_id: Optional[str] = None, - conversation_id: Optional[str] = None, - mode: Optional[Union[str, "_models.TelephonyCallTraceMode"]] = None, + pin: Optional[bool] = None, + additional_search_text: Optional[str] = None, ) -> None: ... @overload @@ -25207,30 +34266,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TelephonyOutboundDestination(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The destination of an outbound call. +class ToolDescription(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Description of a tool that can be used by an agent. - :ivar type: The destination type. Only E.164 phone numbers are currently supported. Required. - "phone_number" - :vartype type: str or ~azure.ai.projects.models.TelephonyOutboundDestinationType - :ivar value: The destination E.164 phone number. Required. - :vartype value: str + :ivar name: The name of the tool. + :vartype name: str + :ivar description: A brief description of the tool's purpose. + :vartype description: str """ - type: Union[str, "_models.TelephonyOutboundDestinationType"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The destination type. Only E.164 phone numbers are currently supported. Required. - \"phone_number\"""" - value: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The destination E.164 phone number. Required.""" + name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the tool.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A brief description of the tool's purpose.""" @overload def __init__( self, *, - type: Union[str, "_models.TelephonyOutboundDestinationType"], - value: str, + name: Optional[str] = None, + description: Optional[str] = None, ) -> None: ... @overload @@ -25244,34 +34299,22 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TelephonyOutboundRetryPolicy(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The retry policy for one durable outbound call intent. ``max_attempts`` includes the first - attempt. Strategy-specific settings are defined by the derived policy. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - TelephonyOutboundFixedIntervalRetryPolicy +class ToolProjectConnection(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A project connection resource. - :ivar type: The retry strategy. Only fixed-interval retries are currently supported. Required. - "fixed_interval" - :vartype type: str or ~azure.ai.projects.models.TelephonyOutboundRetryPolicyType - :ivar max_attempts: The maximum number of provider attempts, including the first attempt. - Defaults to 1. - :vartype max_attempts: int + :ivar project_connection_id: A project connection in a ToolProjectConnectionList attached to + this tool. Required. + :vartype project_connection_id: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The retry strategy. Only fixed-interval retries are currently supported. Required. - \"fixed_interval\"""" - max_attempts: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The maximum number of provider attempts, including the first attempt. Defaults to 1.""" + project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A project connection in a ToolProjectConnectionList attached to this tool. Required.""" @overload def __init__( self, *, - type: str, - max_attempts: Optional[int] = None, + project_connection_id: str, ) -> None: ... @overload @@ -25285,34 +34328,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TelephonyOutboundFixedIntervalRetryPolicy( - TelephonyOutboundRetryPolicy, discriminator="fixed_interval" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """The frozen fixed-interval retry policy returned for an outbound call or campaign. +class ToolSearchToolboxTool( + ToolboxTool, discriminator="toolbox_search" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A toolbox search tool stored in a toolbox. - :ivar max_attempts: The maximum number of provider attempts, including the first attempt. - Defaults to 1. - :vartype max_attempts: int - :ivar type: The fixed-interval retry strategy. Required. Retry after a fixed interval between - attempts. - :vartype type: str or ~azure.ai.projects.models.FIXED_INTERVAL - :ivar interval: The fixed delay in seconds between attempts. Required. - :vartype interval: ~datetime.timedelta + :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 type: The type of the tool. Always ``toolbox_search``. Required. TOOLBOX_SEARCH. + :vartype type: str or ~azure.ai.projects.models.TOOLBOX_SEARCH """ - type: Literal[TelephonyOutboundRetryPolicyType.FIXED_INTERVAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The fixed-interval retry strategy. Required. Retry after a fixed interval between attempts.""" - interval: datetime.timedelta = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" - ) - """The fixed delay in seconds between attempts. Required.""" + type: Literal[ToolboxToolType.TOOLBOX_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``toolbox_search``. Required. TOOLBOX_SEARCH.""" @overload def __init__( self, *, - interval: datetime.timedelta, - max_attempts: Optional[int] = None, + name: Optional[str] = None, + description: Optional[str] = None, + tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, ) -> None: ... @overload @@ -25324,37 +34366,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TelephonyOutboundRetryPolicyType.FIXED_INTERVAL # type: ignore + self.type = ToolboxToolType.TOOLBOX_SEARCH # type: ignore -class TelephonyTransferTarget(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A named destination to which the voice agent may transfer a call. +class ToolSearchToolParam( + Tool, discriminator="tool_search" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Tool search tool. - :ivar name: The unique name exposed to the voice agent for this transfer target. Required. - :vartype name: str - :ivar description: A description that helps the voice agent decide when to use this target. - Required. + :ivar type: The type of the tool. Always ``tool_search``. Required. TOOL_SEARCH. + :vartype type: str or ~azure.ai.projects.models.TOOL_SEARCH + :ivar execution: Whether tool search is executed by the server or by the client. Known values + are: "server" and "client". + :vartype execution: str or ~azure.ai.projects.models.ToolSearchExecutionType + :ivar description: :vartype description: str - :ivar destination: The provider-specific transfer destination. Required. - :vartype destination: ~azure.ai.projects.models.TelephonyTransferDestination + :ivar parameters: + :vartype parameters: ~azure.ai.projects.models.EmptyModelParam """ - name: str = rest_field(visibility=["read", "create"]) - """The unique name exposed to the voice agent for this transfer target. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A description that helps the voice agent decide when to use this target. Required.""" - destination: "_models.TelephonyTransferDestination" = rest_field( + type: Literal[ToolType.TOOL_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``tool_search``. Required. TOOL_SEARCH.""" + execution: Optional[Union[str, "_models.ToolSearchExecutionType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Whether tool search is executed by the server or by the client. Known values are: \"server\" + and \"client\".""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + parameters: Optional["_models.EmptyModelParam"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The provider-specific transfer destination. Required.""" @overload def __init__( self, *, - name: str, - description: str, - destination: "_models.TelephonyTransferDestination", + execution: Optional[Union[str, "_models.ToolSearchExecutionType"]] = None, + description: Optional[str] = None, + parameters: Optional["_models.EmptyModelParam"] = None, ) -> None: ... @overload @@ -25366,27 +34415,41 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = ToolType.TOOL_SEARCH # type: ignore -class TelephonyTransferTargets(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The telephony transfer targets configured for one voice agent. +class ToolUseFineTuningDataGenerationJobConfiguration( + DataGenerationJobConfiguration, discriminator="tool_use" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The configuration for a data generation job with ToolUse type. This is a preview feature used + only for fine-tuning scenarios. - :ivar transfer_targets: The complete set of destinations to which the voice agent may transfer - calls. An empty array clears all targets when replacing the configuration. Required. - :vartype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + :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 + :ivar max_samples: Maximum number of samples to generate, up to service-defined limits. + Required. + :vartype max_samples: int """ - transfer_targets: list["_models.TelephonyTransferTarget"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The complete set of destinations to which the voice agent may transfer calls. An empty array - clears all targets when replacing the configuration. Required.""" + 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.""" + max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of samples to generate, up to service-defined limits. Required.""" @overload def __init__( self, *, - transfer_targets: list["_models.TelephonyTransferTarget"], + max_samples: int, + train_split: Optional[float] = None, + model_options: Optional["_models.DataGenerationModelOptions"] = None, ) -> None: ... @overload @@ -25398,33 +34461,48 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = DataGenerationJobType.TOOL_USE # type: ignore -class TextResponseFormat(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """An object specifying the format that the model must output. Configuring ``{ "type": - "json_schema" }`` enables Structured Outputs, which ensures the model will match your supplied - JSON schema. Learn more in the `Structured Outputs guide `_. - The default format is ``{ "type": "text" }`` with no additional options. *Not recommended for - gpt-4o and newer models:** Setting to ``{ "type": "json_object" }`` enables the older JSON - mode, which ensures the message the model generates is valid JSON. Using ``json_schema`` is - preferred for models that support it. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - TextResponseFormatJsonObject, TextResponseFormatJsonSchema, TextResponseFormatText +class TracesDataGenerationJobConfiguration( + DataGenerationJobConfiguration, discriminator="traces" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The configuration for a data generation job with Traces type. - :ivar type: Required. Known values are: "text", "json_schema", and "json_object". - :vartype type: str or ~azure.ai.projects.models.TextResponseFormatConfigurationType + :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 + :ivar max_samples: Maximum number of samples to generate, up to service-defined limits. If + omitted, sampling is turned off. + :vartype max_samples: int + :ivar redact_private_content: Whether to redact private content from traces. When omitted or + set to true, private content is redacted. Set to false to opt out of redaction. + :vartype redact_private_content: bool """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"text\", \"json_schema\", and \"json_object\".""" + 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.""" + max_samples: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of samples to generate, up to service-defined limits. If omitted, sampling is + turned off.""" + redact_private_content: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to redact private content from traces. When omitted or set to true, private content is + redacted. Set to false to opt out of redaction.""" @overload def __init__( self, *, - type: str, + train_split: Optional[float] = None, + model_options: Optional["_models.DataGenerationModelOptions"] = None, + max_samples: Optional[int] = None, + redact_private_content: Optional[bool] = None, ) -> None: ... @overload @@ -25436,22 +34514,73 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = DataGenerationJobType.TRACES # type: ignore -class TextResponseFormatJsonObject(TextResponseFormat, discriminator="json_object"): - """JSON object. +class TracesDataGenerationJobSource( + DataGenerationJobSource, discriminator="traces" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Traces source for data generation jobs — conversation traces from Application Insights. - :ivar type: The type of response format being defined. Always ``json_object``. Required. - JSON_OBJECT. - :vartype type: str or ~azure.ai.projects.models.JSON_OBJECT + :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 + :ivar trace_ids: Optional explicit list of trace IDs to include. + :vartype trace_ids: list[str] """ - type: Literal[TextResponseFormatConfigurationType.JSON_OBJECT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of response format being defined. Always ``json_object``. Required. JSON_OBJECT.""" + 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.""" + trace_ids: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional explicit list of trace IDs to include.""" @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, + trace_ids: Optional[list[str]] = None, ) -> None: ... @overload @@ -25463,49 +34592,71 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TextResponseFormatConfigurationType.JSON_OBJECT # type: ignore + self.type = DataGenerationJobSourceType.TRACES # type: ignore -class TextResponseFormatJsonSchema( - TextResponseFormat, discriminator="json_schema" +class TracesEvaluatorGenerationJobSource( + EvaluatorGenerationJobSource, discriminator="traces" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """JSON schema. + """Traces source for evaluator generation jobs — conversation traces from Application Insights. - :ivar type: The type of response format being defined. Always ``json_schema``. Required. - JSON_SCHEMA. - :vartype type: str or ~azure.ai.projects.models.JSON_SCHEMA - :ivar description: A description of what the response format is for, used by the model to - determine how to respond in the format. + :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 name: The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and - dashes, with a maximum length of 64. Required. - :vartype name: str - :ivar schema: Required. - :vartype schema: dict[str, any] - :ivar strict: - :vartype strict: bool + :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[TextResponseFormatConfigurationType.JSON_SCHEMA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of response format being defined. Always ``json_schema``. Required. JSON_SCHEMA.""" description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A description of what the response format is for, used by the model to determine how to respond - in the format.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with - a maximum length of 64. Required.""" - schema: dict[str, Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - strict: Optional[bool] = 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, *, - name: str, - schema: dict[str, Any], + start_time: datetime.datetime, description: Optional[str] = None, - strict: Optional[bool] = None, + agent_id: Optional[str] = None, + agent_name: Optional[str] = None, + agent_version: Optional[str] = None, + end_time: Optional[datetime.datetime] = None, ) -> None: ... @overload @@ -25517,22 +34668,114 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TextResponseFormatConfigurationType.JSON_SCHEMA # type: ignore + self.type = EvaluatorGenerationJobSourceType.TRACES # type: ignore -class TextResponseFormatText(TextResponseFormat, discriminator="text"): - """Text. +class TranscriptionLanguage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A language detected in transcribed audio. - :ivar type: The type of response format being defined. Always ``text``. Required. TEXT. - :vartype type: str or ~azure.ai.projects.models.TEXT + :ivar code: The code of a language detected in the audio. Required. + :vartype code: str """ - type: Literal[TextResponseFormatConfigurationType.TEXT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of response format being defined. Always ``text``. Required. TEXT.""" + code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The code of a language detected in the audio. Required.""" + + @overload + def __init__( + self, + *, + code: 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 TranscriptTextUsageDuration( + CreateTranscriptionResponseJsonUsage, discriminator="duration" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Duration Usage. + + :ivar type: The type of the usage object. Always ``duration`` for this variant. Required. + DURATION. + :vartype type: str or ~azure.ai.projects.models.DURATION + :ivar seconds: Duration of the input audio in seconds. Required. + :vartype seconds: ~datetime.timedelta + """ + + type: Literal[CreateTranscriptionResponseJsonUsageType.DURATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the usage object. Always ``duration`` for this variant. Required. DURATION.""" + seconds: datetime.timedelta = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + ) + """Duration of the input audio in seconds. Required.""" + + @overload + def __init__( + self, + *, + seconds: datetime.timedelta, + ) -> 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 = CreateTranscriptionResponseJsonUsageType.DURATION # type: ignore + + +class TranscriptTextUsageTokens( + CreateTranscriptionResponseJsonUsage, discriminator="tokens" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Token Usage. + + :ivar type: The type of the usage object. Always ``tokens`` for this variant. Required. TOKENS. + :vartype type: str or ~azure.ai.projects.models.TOKENS + :ivar input_tokens: Number of input tokens billed for this request. Required. + :vartype input_tokens: int + :ivar input_token_details: Details about the input tokens billed for this request. + :vartype input_token_details: + ~azure.ai.projects.models.TranscriptTextUsageTokensInputTokenDetails + :ivar output_tokens: Number of output tokens generated. Required. + :vartype output_tokens: int + :ivar total_tokens: Total number of tokens used (input + output). Required. + :vartype total_tokens: int + """ + + type: Literal[CreateTranscriptionResponseJsonUsageType.TOKENS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the usage object. Always ``tokens`` for this variant. Required. TOKENS.""" + input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of input tokens billed for this request. Required.""" + input_token_details: Optional["_models.TranscriptTextUsageTokensInputTokenDetails"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Details about the input tokens billed for this request.""" + output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of output tokens generated. Required.""" + total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total number of tokens used (input + output). Required.""" @overload def __init__( self, + *, + input_tokens: int, + output_tokens: int, + total_tokens: int, + input_token_details: Optional["_models.TranscriptTextUsageTokensInputTokenDetails"] = None, ) -> None: ... @overload @@ -25544,32 +34787,29 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = TextResponseFormatConfigurationType.TEXT # type: ignore + self.type = CreateTranscriptionResponseJsonUsageType.TOKENS # type: ignore -class TimerRoutineTrigger( - RoutineTrigger, discriminator="timer" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A one-shot timer routine trigger. +class TranscriptTextUsageTokensInputTokenDetails( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """TranscriptTextUsageTokensInputTokenDetails. - :ivar type: The trigger type. Required. A one-shot timer trigger. - :vartype type: str or ~azure.ai.projects.models.TIMER - :ivar at: The UTC date and time at which the timer fires. - :vartype at: ~datetime.datetime + :ivar text_tokens: + :vartype text_tokens: int + :ivar audio_tokens: + :vartype audio_tokens: int """ - 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: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The UTC date and time at which the timer fires.""" + text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - at: Optional[datetime.datetime] = None, + text_tokens: Optional[int] = None, + audio_tokens: Optional[int] = None, ) -> None: ... @overload @@ -25581,50 +34821,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RoutineTriggerType.TIMER # type: ignore -class ToolboxObject(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A toolbox that stores reusable tool definitions for agents. +class TwilioTelephonyBinding( + TelephonyBinding, discriminator="twilio" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Twilio binding owned by a voice agent. - :ivar id: The unique identifier of the toolbox. Required. + :ivar id: The service-generated binding identifier. Required. :vartype id: str - :ivar name: The name of the toolbox. Required. - :vartype name: str - :ivar updated_at: The Unix timestamp (seconds) when the toolbox was last updated. This value - changes when a new toolbox version is created or the toolbox is updated. Required. - :vartype updated_at: ~datetime.datetime - :ivar versions: The versions associated with the toolbox. Required. - :vartype versions: ~azure.ai.projects.models.ToolboxVersions - :ivar default_version: The version identifier that the toolbox currently points to. Defaults to - the latest version. Can be changed via updateToolbox. Required. - :vartype default_version: str + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated incoming address: an HTTPS webhook for + webhook-based providers or a SIP/SIPS ingress URI for SIP. Required. + :vartype incoming_call_url: str + :ivar provider: The Twilio provider. Required. Twilio Programmable Voice. + :vartype provider: str or ~azure.ai.projects.models.TWILIO + :ivar phone_number: The Twilio E.164 phone number. Required. + :vartype phone_number: str """ - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique identifier of the toolbox. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the toolbox. Required.""" - updated_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (seconds) when the toolbox was last updated. This value changes when a new - toolbox version is created or the toolbox is updated. Required.""" - versions: "_models.ToolboxVersions" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The versions associated with the toolbox. Required.""" - default_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version identifier that the toolbox currently points to. Defaults to the latest version. - Can be changed via updateToolbox. Required.""" + provider: Literal[TelephonyProvider.TWILIO] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Twilio provider. Required. Twilio Programmable Voice.""" + phone_number: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Twilio E.164 phone number. Required.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - name: str, - updated_at: datetime.datetime, - versions: "_models.ToolboxVersions", - default_version: str, + connection_name: str, + phone_number: str, + label: Optional[str] = None, ) -> None: ... @overload @@ -25636,23 +34866,46 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.provider = TelephonyProvider.TWILIO # type: ignore -class ToolboxPolicies(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Policy configuration for a toolbox, including content safety and other governance settings. +class TwilioTelephonyBindingListItem( + TelephonyBindingListItem, discriminator="twilio" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Twilio binding returned in a list, including its entity tag. - :ivar rai_config: Responsible AI content filtering configuration. - :vartype rai_config: ~azure.ai.projects.models.RaiConfig + :ivar id: The service-generated binding identifier. Required. + :vartype id: str + :ivar connection_name: The Foundry connection name for the telephony provider. Required. + :vartype connection_name: str + :ivar label: The optional display label for the binding. + :vartype label: str + :ivar incoming_call_url: The service-generated HTTPS webhook or SIP/SIPS ingress URI to + configure with the telephony provider. Required. + :vartype incoming_call_url: str + :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this + binding. Required. + :vartype etag: str + :ivar provider: The Twilio provider. Required. Twilio Programmable Voice. + :vartype provider: str or ~azure.ai.projects.models.TWILIO + :ivar phone_number: The Twilio E.164 phone number. Required. + :vartype phone_number: str """ - rai_config: Optional["_models.RaiConfig"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Responsible AI content filtering configuration.""" + provider: Literal[TelephonyProvider.TWILIO] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The Twilio provider. Required. Twilio Programmable Voice.""" + phone_number: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Twilio E.164 phone number. Required.""" @overload def __init__( self, *, - rai_config: Optional["_models.RaiConfig"] = None, + id: str, # pylint: disable=redefined-builtin + connection_name: str, + incoming_call_url: str, + phone_number: str, + label: Optional[str] = None, ) -> None: ... @overload @@ -25664,36 +34917,29 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.provider = TelephonyProvider.TWILIO # type: ignore -class ToolboxSearchPreviewToolboxTool( - ToolboxTool, discriminator="toolbox_search_preview" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A toolbox search tool stored in a toolbox. +class UpdateModelVersionRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Request body for updating a model version. Only description and tags can be modified. - :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. + :ivar description: The asset description text. :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 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 tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] """ - type: Literal[ToolboxToolType.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.""" + 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, *, - name: Optional[str] = None, description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -25705,29 +34951,48 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolboxToolType.TOOLBOX_SEARCH_PREVIEW # type: ignore - -class ToolboxShellEnvironment(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """An execution environment for a shell tool stored in a toolbox. This environment model is scoped - to toolbox configuration and does not modify the OpenAI shell environment contract. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ToolboxShellContainerAutoEnvironment, ToolboxShellContainerReferenceEnvironment +class UpdateTelephonyBindingRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The request to update an existing telephony binding. Every property is optional and the + binding's provider is immutable. - :ivar type: The type of the shell execution environment. Required. Default value is None. - :vartype type: str + :ivar label: Replacement label: omit to preserve, null/blank to clear. Trimmed before length + validation. + :vartype label: str + :ivar connection_name: Replacement same-project connection for Teams or SIP (SipInbound only); + immutable for Twilio. Null/blank names are invalid. + :vartype connection_name: str + :ivar phone_number: Teams/SIP display number, not SIP routing. Omit to preserve; + null/empty/blank clears. Unsupported for Twilio. + :vartype phone_number: str + :ivar allowed_calling_numbers: SIP caller restrictions: omit to preserve, [] to clear; null is + invalid. Network restrictions belong to the connection. + :vartype allowed_calling_numbers: list[str] """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of the shell execution environment. Required. Default value is None.""" + label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Replacement label: omit to preserve, null/blank to clear. Trimmed before length validation.""" + connection_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Replacement same-project connection for Teams or SIP (SipInbound only); immutable for Twilio. + Null/blank names are invalid.""" + phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Teams/SIP display number, not SIP routing. Omit to preserve; null/empty/blank clears. + Unsupported for Twilio.""" + allowed_calling_numbers: Optional[list[str]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """SIP caller restrictions: omit to preserve, [] to clear; null is invalid. Network restrictions + belong to the connection.""" @overload def __init__( self, *, - type: str, + label: Optional[str] = None, + connection_name: Optional[str] = None, + phone_number: Optional[str] = None, + allowed_calling_numbers: Optional[list[str]] = None, ) -> None: ... @overload @@ -25741,52 +35006,23 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolboxShellContainerAutoEnvironment( - ToolboxShellEnvironment, discriminator="container_auto" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """An automatically provisioned container environment for a shell tool stored in a toolbox. +class UpdateToolboxRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """UpdateToolboxRequest. - :ivar type: The type of the shell execution environment. Always ``container_auto``. Required. - Default value is "container_auto". - :vartype type: str - :ivar file_ids: An optional list of uploaded files to make available to your code. - :vartype file_ids: list[str] - :ivar memory_limit: Known values are: "1g", "4g", "16g", and "64g". - :vartype memory_limit: str or ~azure.ai.projects.models.ContainerMemoryLimit - :ivar skills: An optional list of skills referenced by id or inline data. - :vartype skills: list[~azure.ai.projects.models.ContainerSkill] - :ivar network_policy: The network access policy for the container. When omitted, the service - defaults to disabled outbound network access. - :vartype network_policy: ~azure.ai.projects.models.ToolboxShellNetworkPolicy + :ivar 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. + :vartype default_version: str """ - type: Literal["container_auto"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the shell execution environment. Always ``container_auto``. Required. Default value - is \"container_auto\".""" - file_ids: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional list of uploaded files to make available to your code.""" - memory_limit: Optional[Union[str, "_models.ContainerMemoryLimit"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Known values are: \"1g\", \"4g\", \"16g\", and \"64g\".""" - skills: Optional[list["_models.ContainerSkill"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """An optional list of skills referenced by id or inline data.""" - network_policy: Optional["_models.ToolboxShellNetworkPolicy"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The network access policy for the container. When omitted, the service defaults to disabled - outbound network access.""" + default_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """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.""" @overload def __init__( self, *, - file_ids: Optional[list[str]] = None, - memory_limit: Optional[Union[str, "_models.ContainerMemoryLimit"]] = None, - skills: Optional[list["_models.ContainerSkill"]] = None, - network_policy: Optional["_models.ToolboxShellNetworkPolicy"] = None, + default_version: str, ) -> None: ... @overload @@ -25798,32 +35034,34 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "container_auto" # type: ignore -class ToolboxShellContainerReferenceEnvironment( - ToolboxShellEnvironment, discriminator="container_reference" +class UserConversationSimulationAudioEffectsConfiguration( + _Model ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """An existing container environment for a shell tool stored in a toolbox. + """Configures effects applied to simulated conversation audio. - :ivar type: The type of the shell execution environment. Always ``container_reference``. - Required. Default value is "container_reference". - :vartype type: str - :ivar container_id: The ID of the referenced container. Required. - :vartype container_id: str + :ivar effects: Effects to apply to simulated audio. + :vartype effects: list[str or ~azure.ai.projects.models.UserConversationSimulationAudioEffect] + :ivar volume_percentage: Volume of the configured audio effects, as a percentage from 1 through + 100. When omitted, the service defaults to 15. + :vartype volume_percentage: int """ - type: Literal["container_reference"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the shell execution environment. Always ``container_reference``. Required. Default - value is \"container_reference\".""" - container_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ID of the referenced container. Required.""" + effects: Optional[list[Union[str, "_models.UserConversationSimulationAudioEffect"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Effects to apply to simulated audio.""" + volume_percentage: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Volume of the configured audio effects, as a percentage from 1 through 100. When omitted, the + service defaults to 15.""" @overload def __init__( self, *, - container_id: str, + effects: Optional[list[Union[str, "_models.UserConversationSimulationAudioEffect"]]] = None, + volume_percentage: Optional[int] = None, ) -> None: ... @overload @@ -25835,28 +35073,58 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "container_reference" # type: ignore - -class ToolboxShellNetworkPolicy(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Network access policy for an automatically provisioned toolbox shell container. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ToolboxShellNetworkPolicyDisabled +class UserConversationSimulationConfiguration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configures the number, length, audio effects, and simulated user behavior of conversations. - :ivar type: The type of network access policy. Required. Default value is None. - :vartype type: str + :ivar max_num_turns: Hard limit on turns in each conversation. When omitted, the service + defaults to 20. + :vartype max_num_turns: int + :ivar conversation_repetitions: Number of independent conversation repetitions for each test + case. Defaults to 1 when not specified at either the data-source or test-case level. + :vartype conversation_repetitions: int + :ivar desired_num_turns: Target number of turns in each conversation. The effective value + cannot exceed the effective ``max_num_turns``. When omitted, no target is set and the + simulation model determines the conversation length dynamically from the scenario. + :vartype desired_num_turns: int + :ivar audio_effects: Audio effects applied to voice conversation simulations. This property is + ignored for text-only simulations. + :vartype audio_effects: + ~azure.ai.projects.models.UserConversationSimulationAudioEffectsConfiguration + :ivar user_behavior: Conversation behavior of the simulated user. + :vartype user_behavior: + ~azure.ai.projects.models.UserConversationSimulationUserBehaviorConfiguration """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of network access policy. Required. Default value is None.""" + max_num_turns: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Hard limit on turns in each conversation. When omitted, the service defaults to 20.""" + conversation_repetitions: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of independent conversation repetitions for each test case. Defaults to 1 when not + specified at either the data-source or test-case level.""" + desired_num_turns: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Target number of turns in each conversation. The effective value cannot exceed the effective + ``max_num_turns``. When omitted, no target is set and the simulation model determines the + conversation length dynamically from the scenario.""" + audio_effects: Optional["_models.UserConversationSimulationAudioEffectsConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Audio effects applied to voice conversation simulations. This property is ignored for text-only + simulations.""" + user_behavior: Optional["_models.UserConversationSimulationUserBehaviorConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Conversation behavior of the simulated user.""" @overload def __init__( self, *, - type: str, + max_num_turns: Optional[int] = None, + conversation_repetitions: Optional[int] = None, + desired_num_turns: Optional[int] = None, + audio_effects: Optional["_models.UserConversationSimulationAudioEffectsConfiguration"] = None, + user_behavior: Optional["_models.UserConversationSimulationUserBehaviorConfiguration"] = None, ) -> None: ... @overload @@ -25870,21 +35138,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolboxShellNetworkPolicyDisabled(ToolboxShellNetworkPolicy, discriminator="disabled"): - """A network policy that disables outbound access from a toolbox shell container. +class UserConversationSimulationInterruptionConfiguration( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Configuration for simulated user interruption behavior. - :ivar type: The type of network access policy. Always ``disabled``. Required. Default value is - "disabled". + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + UserConversationSimulationDefaultInterruptionConfiguration + + :ivar type: The interruption type. Required. Default value is None. :vartype type: str """ - type: Literal["disabled"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of network access policy. Always ``disabled``. Required. Default value is - \"disabled\".""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The interruption type. Required. Default value is None.""" @overload def __init__( self, + *, + type: str, ) -> None: ... @overload @@ -25896,28 +35170,23 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "disabled" # type: ignore - -class ToolboxSkill(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A skill source included in a toolbox. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ToolboxSkillReference +class UserConversationSimulationDefaultInterruptionConfiguration( + UserConversationSimulationInterruptionConfiguration, discriminator="default" +): # pylint: disable=name-too-long + """Configures the default interruption behavior for the simulated user. - :ivar type: The type of skill source. Required. Default value is None. + :ivar type: The interruption type, always ``default``. Required. Default value is "default". :vartype type: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of skill source. Required. Default value is None.""" + type: Literal["default"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The interruption type, always ``default``. Required. Default value is \"default\".""" @overload def __init__( self, - *, - type: str, ) -> None: ... @overload @@ -25929,36 +35198,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = "default" # type: ignore -class ToolboxSkillReference( - ToolboxSkill, discriminator="skill_reference" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A reference to an existing skill to include in a toolbox. +class UserConversationSimulationTestCase(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Defines one test scenario. Simulation configuration properties specified here override the + corresponding data-source defaults. - :ivar type: The type of skill source. Required. Default value is "skill_reference". - :vartype type: str - :ivar name: The name of the skill. Required. - :vartype name: str - :ivar version: The version of the skill. If not specified, the skill's default version is used. - When a version is specified, the reference is pinned to that immutable version. - :vartype version: str + :ivar test_case_id: Identifier for the test case. When omitted, the service generates a random + identifier. + :vartype test_case_id: str + :ivar test_case_category: Category used to group related test cases. When omitted, the service + leaves the category null. + :vartype test_case_category: str + :ivar test_case_description: Scenario, simulated user goal, and behavioral constraints that + guide the conversation. The length must be from 1 through 2,500 characters. + :vartype test_case_description: str + :ivar simulation_configuration: Configuration for conversations generated from this test case. + Each specified property overrides the corresponding property in + ``default_simulation_configuration``. + :vartype simulation_configuration: + ~azure.ai.projects.models.UserConversationSimulationConfiguration """ - type: Literal["skill_reference"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of skill source. Required. Default value is \"skill_reference\".""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the skill. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version of the skill. If not specified, the skill's default version is used. When a version - is specified, the reference is pinned to that immutable version.""" + test_case_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Identifier for the test case. When omitted, the service generates a random identifier.""" + test_case_category: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Category used to group related test cases. When omitted, the service leaves the category null.""" + test_case_description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Scenario, simulated user goal, and behavioral constraints that guide the conversation. The + length must be from 1 through 2,500 characters.""" + simulation_configuration: Optional["_models.UserConversationSimulationConfiguration"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Configuration for conversations generated from this test case. Each specified property + overrides the corresponding property in ``default_simulation_configuration``.""" @overload def __init__( self, *, - name: str, - version: Optional[str] = None, + test_case_id: Optional[str] = None, + test_case_category: Optional[str] = None, + test_case_description: Optional[str] = None, + simulation_configuration: Optional["_models.UserConversationSimulationConfiguration"] = None, ) -> None: ... @overload @@ -25970,82 +35253,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "skill_reference" # type: ignore -class ToolboxVersionObject(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A specific version of a toolbox. - - :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. +class UserConversationSimulationUserBehaviorConfiguration( + _Model +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Configures conversation behavior for the simulated user. - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Required. - :vartype metadata: dict[str, str] - :ivar id: The unique identifier of the toolbox version. Required. - :vartype id: str - :ivar name: The name of the toolbox. Required. - :vartype name: str - :ivar version: The version identifier of the toolbox. Toolbox versions are immutable and every - update creates a new version. Required. - :vartype version: str - :ivar description: A human-readable description of the toolbox. - :vartype description: str - :ivar created_at: The Unix timestamp (seconds) when the toolbox version was created. Required. - :vartype created_at: ~datetime.datetime - :ivar tools: The list of tools contained in this toolbox version. Required. - :vartype tools: list[~azure.ai.projects.models.ToolboxTool] - :ivar skills: The list of skill sources included in this toolbox version. - :vartype skills: list[~azure.ai.projects.models.ToolboxSkill] - :ivar policies: Policy configuration for the toolbox version. - :vartype policies: ~azure.ai.projects.models.ToolboxPolicies + :ivar interruption: Configures how the simulated user interrupts the target while it is + speaking. Omit to disable interruption. + :vartype interruption: + ~azure.ai.projects.models.UserConversationSimulationInterruptionConfiguration """ - metadata: 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. Required.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique identifier of the toolbox version. Required.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the toolbox. Required.""" - version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version identifier of the toolbox. Toolbox versions are immutable and every update creates - a new version. Required.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A human-readable description of the toolbox.""" - created_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """The Unix timestamp (seconds) when the toolbox version was created. Required.""" - tools: list["_models.ToolboxTool"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The list of tools contained in this toolbox version. Required.""" - skills: Optional[list["_models.ToolboxSkill"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The list of skill sources included in this toolbox version.""" - policies: Optional["_models.ToolboxPolicies"] = rest_field( + interruption: Optional["_models.UserConversationSimulationInterruptionConfiguration"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Policy configuration for the toolbox version.""" + """Configures how the simulated user interrupts the target while it is speaking. Omit to disable + interruption.""" @overload def __init__( self, *, - metadata: dict[str, str], - id: str, # pylint: disable=redefined-builtin - name: str, - version: str, - created_at: datetime.datetime, - tools: list["_models.ToolboxTool"], - description: Optional[str] = None, - skills: Optional[list["_models.ToolboxSkill"]] = None, - policies: Optional["_models.ToolboxPolicies"] = None, + interruption: Optional["_models.UserConversationSimulationInterruptionConfiguration"] = None, ) -> None: ... @overload @@ -26059,21 +35290,37 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolboxVersions(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The versions associated with a toolbox. +class UserProfileMemoryItem( + MemoryItem, discriminator="user_profile" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A memory item specifically containing user profile information extracted from conversations, + such as preferences, interests, and personal details. - :ivar latest: The latest version of the toolbox. Required. - :vartype latest: ~azure.ai.projects.models.ToolboxVersionObject + :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. User profile information extracted from + conversations. + :vartype kind: str or ~azure.ai.projects.models.USER_PROFILE """ - latest: "_models.ToolboxVersionObject" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The latest version of the toolbox. Required.""" + kind: Literal[MemoryItemKind.USER_PROFILE] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The kind of the memory item. Required. User profile information extracted from conversations.""" @overload def __init__( self, *, - latest: "_models.ToolboxVersionObject", + memory_id: str, + updated_at: datetime.datetime, + scope: str, + content: str, ) -> None: ... @overload @@ -26085,58 +35332,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.kind = MemoryItemKind.USER_PROFILE # type: ignore -class ToolChoiceAllowed( - ToolChoiceParam, discriminator="allowed_tools" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Allowed tools. - - :ivar type: Allowed tool configuration type. Always ``allowed_tools``. Required. ALLOWED_TOOLS. - :vartype type: str or ~azure.ai.projects.models.ALLOWED_TOOLS - :ivar mode: Constrains the tools available to the model to a pre-defined set. ``auto`` allows - the model to pick from among the allowed tools and generate a message. ``required`` requires - the model to call one or more of the allowed tools. Required. Is either a Literal["auto"] type - or a Literal["required"] type. - :vartype mode: str or str - :ivar tools: Required. A list of tool definitions that the model should be allowed to call. For - the Responses API, the list of tool definitions might look like: +class VersionIndicator(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Version indicator determining which agent version backs the session. - .. code-block:: json + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VersionRefIndicator - [ - { "type": "function", "name": "get_weather" }, - { "type": "mcp", "server_label": "deepwiki" }, - { "type": "image_generation" } - ] - :vartype tools: list[dict[str, any]] + :ivar type: The type of version indicator. Required. "version_ref" + :vartype type: str or ~azure.ai.projects.models.VersionIndicatorType """ - type: Literal[ToolChoiceParamType.ALLOWED_TOOLS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Allowed tool configuration type. Always ``allowed_tools``. Required. ALLOWED_TOOLS.""" - mode: Literal["auto", "required"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Constrains the tools available to the model to a pre-defined set. ``auto`` allows the model to - pick from among the allowed tools and generate a message. ``required`` requires the model to - call one or more of the allowed tools. Required. Is either a Literal[\"auto\"] type or a - Literal[\"required\"] type.""" - tools: list[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required. A list of tool definitions that the model should be allowed to call. For the - Responses API, the list of tool definitions might look like: - - .. code-block:: json - - [ - { \"type\": \"function\", \"name\": \"get_weather\" }, - { \"type\": \"mcp\", \"server_label\": \"deepwiki\" }, - { \"type\": \"image_generation\" } - ]""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of version indicator. Required. \"version_ref\"""" @overload def __init__( self, *, - mode: Literal["auto", "required"], - tools: list[dict[str, Any]], + type: str, ) -> None: ... @overload @@ -26148,23 +35365,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.ALLOWED_TOOLS # type: ignore -class ToolChoiceCodeInterpreter(ToolChoiceParam, discriminator="code_interpreter"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VersionRefIndicator( + VersionIndicator, discriminator="version_ref" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Version indicator that references a specific agent version by name. - :ivar type: Required. CODE_INTERPRETER. - :vartype type: str or ~azure.ai.projects.models.CODE_INTERPRETER + :ivar type: Discriminator value for version_ref. Required. Direct reference to a specific agent + version. + :vartype type: str or ~azure.ai.projects.models.VERSION_REF + :ivar agent_version: The agent version identifier returned by the agent version APIs. Required. + :vartype agent_version: str """ - type: Literal[ToolChoiceParamType.CODE_INTERPRETER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. CODE_INTERPRETER.""" + type: Literal[VersionIndicatorType.VERSION_REF] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Discriminator value for version_ref. Required. Direct reference to a specific agent version.""" + agent_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent version identifier returned by the agent version APIs. Required.""" @overload def __init__( self, + *, + agent_version: str, ) -> None: ... @overload @@ -26176,23 +35400,26 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.CODE_INTERPRETER # type: ignore + self.type = VersionIndicatorType.VERSION_REF # type: ignore -class ToolChoiceComputer(ToolChoiceParam, discriminator="computer"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VersionSelector(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """VersionSelector. - :ivar type: Required. COMPUTER. - :vartype type: str or ~azure.ai.projects.models.COMPUTER + :ivar version_selection_rules: Required. + :vartype version_selection_rules: list[~azure.ai.projects.models.VersionSelectionRule] """ - type: Literal[ToolChoiceParamType.COMPUTER] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. COMPUTER.""" + version_selection_rules: list["_models.VersionSelectionRule"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" @overload def __init__( self, + *, + version_selection_rules: list["_models.VersionSelectionRule"], ) -> None: ... @overload @@ -26204,23 +35431,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.COMPUTER # type: ignore -class ToolChoiceComputerUse(ToolChoiceParam, discriminator="computer_use"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VoiceAgentAnimationConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Animation settings for a voice-agent session. - :ivar type: Required. COMPUTER_USE. - :vartype type: str or ~azure.ai.projects.models.COMPUTER_USE + :ivar model_name: The animation model name. + :vartype model_name: str + :ivar outputs: The requested animation output kinds. + :vartype outputs: list[str or ~azure.ai.projects.models.VoiceAgentAnimationOutputType] """ - type: Literal[ToolChoiceParamType.COMPUTER_USE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. COMPUTER_USE.""" + model_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The animation model name.""" + outputs: Optional[list[Union[str, "_models.VoiceAgentAnimationOutputType"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The requested animation output kinds.""" @overload def __init__( self, + *, + model_name: Optional[str] = None, + outputs: Optional[list[Union[str, "_models.VoiceAgentAnimationOutputType"]]] = None, ) -> None: ... @overload @@ -26232,23 +35466,33 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.COMPUTER_USE # type: ignore -class ToolChoiceComputerUsePreview(ToolChoiceParam, discriminator="computer_use_preview"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VoiceAgentAudioConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The audio configuration for a voice agent. These values are session defaults and may be + overridden when connecting. - :ivar type: Required. COMPUTER_USE_PREVIEW. - :vartype type: str or ~azure.ai.projects.models.COMPUTER_USE_PREVIEW + :ivar input: Input (microphone) audio configuration. + :vartype input: ~azure.ai.projects.models.VoiceAgentAudioInputConfig + :ivar output: Output (agent speech) audio configuration. + :vartype output: ~azure.ai.projects.models.VoiceAgentAudioOutputConfig """ - type: Literal[ToolChoiceParamType.COMPUTER_USE_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. COMPUTER_USE_PREVIEW.""" + input: Optional["_models.VoiceAgentAudioInputConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Input (microphone) audio configuration.""" + output: Optional["_models.VoiceAgentAudioOutputConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Output (agent speech) audio configuration.""" @overload def __init__( self, + *, + input: Optional["_models.VoiceAgentAudioInputConfig"] = None, + output: Optional["_models.VoiceAgentAudioOutputConfig"] = None, ) -> None: ... @overload @@ -26260,30 +35504,56 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.COMPUTER_USE_PREVIEW # type: ignore -class ToolChoiceCustom( - ToolChoiceParam, discriminator="custom" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Custom tool. +class VoiceAgentAudioInputConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Input audio configuration for a voice agent. - :ivar type: For custom tool calling, the type is always ``custom``. Required. CUSTOM. - :vartype type: str or ~azure.ai.projects.models.CUSTOM - :ivar name: The name of the custom tool to call. Required. - :vartype name: str + :ivar format: The input audio format. + :vartype format: ~azure.ai.projects.models.RealtimeAudioFormats + :ivar noise_reduction: Input noise reduction. Set to null to disable. + :vartype noise_reduction: ~azure.ai.projects.models.VoiceAgentNoiseReduction + :ivar turn_detection: Turn (end-of-speech) detection. Server-side turn detection is enabled by + default; set to null to disable it, in which case the client must trigger responses manually. + :vartype turn_detection: ~azure.ai.projects.models.VoiceAgentTurnDetectionConfig + :ivar echo_cancellation: Optional server-side echo cancellation settings. + :vartype echo_cancellation: ~azure.ai.projects.models.VoiceAgentEchoCancellation + :ivar transcription: Asynchronous input-audio transcription. Set to null to disable + transcription. + :vartype transcription: ~azure.ai.projects.models.VoiceAgentInputTranscription """ - type: Literal[ToolChoiceParamType.CUSTOM] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """For custom tool calling, the type is always ``custom``. Required. CUSTOM.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the custom tool to call. Required.""" + format: Optional["_models.RealtimeAudioFormats"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The input audio format.""" + noise_reduction: Optional["_models.VoiceAgentNoiseReduction"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Input noise reduction. Set to null to disable.""" + turn_detection: Optional["_models.VoiceAgentTurnDetectionConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Turn (end-of-speech) detection. Server-side turn detection is enabled by default; set to null + to disable it, in which case the client must trigger responses manually.""" + echo_cancellation: Optional["_models.VoiceAgentEchoCancellation"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional server-side echo cancellation settings.""" + transcription: Optional["_models.VoiceAgentInputTranscription"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Asynchronous input-audio transcription. Set to null to disable transcription.""" @overload def __init__( self, *, - name: str, + format: Optional["_models.RealtimeAudioFormats"] = None, + noise_reduction: Optional["_models.VoiceAgentNoiseReduction"] = None, + turn_detection: Optional["_models.VoiceAgentTurnDetectionConfig"] = None, + echo_cancellation: Optional["_models.VoiceAgentEchoCancellation"] = None, + transcription: Optional["_models.VoiceAgentInputTranscription"] = None, ) -> None: ... @overload @@ -26295,23 +35565,125 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.CUSTOM # type: ignore -class ToolChoiceFileSearch(ToolChoiceParam, discriminator="file_search"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VoiceAgentVoiceConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Voice output configuration. Inline subagents use it directly as their voice override, and the + session-level + output audio configuration extends it. + Provider-specific fields are selected by ``voice_type``: - :ivar type: Required. FILE_SEARCH. - :vartype type: str or ~azure.ai.projects.models.FILE_SEARCH + * `openai`: `voice` and `speed`. + * `azure-standard`: `voice`, `voice_locale`, `speed`, `voice_temperature`, `custom_lexicon_url`, + `custom_text_normalization_url`, `prefer_locales`, `style`, `pitch`, and `volume`. + * `azure-custom`: all `azure-standard` fields except `style`, plus `custom_voice_endpoint_id`. + * `azure-personal`: all `azure-standard` fields except `style`, plus `personal_voice_model`. + * `avatar-voice-sync`: all `azure-standard` fields except `voice` and `style`, plus `personal_voice_model`; the + voice name is derived from the avatar. + * `azure-realtime-native`: `voice` and `speed`. + + :ivar voice: The voice name or identifier. Applies to ``openai``, ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``azure-realtime-native``. It does not apply to + ``avatar-voice-sync``, which derives the voice name from the avatar. + :vartype voice: str + :ivar voice_type: The voice implementation. Known values are: "openai", "azure-standard", + "azure-custom", "azure-personal", "avatar-voice-sync", and "azure-realtime-native". + :vartype voice_type: str or ~azure.ai.projects.models.VoiceType + :ivar voice_locale: The enforced BCP-47 output locale. Applies to ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype voice_locale: str + :ivar speed: The numeric output speed multiplier. Applies to all known ``voice_type`` values + and defaults to 1. + :vartype speed: float + :ivar voice_temperature: The voice variation temperature. Applies to ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype voice_temperature: float + :ivar custom_lexicon_url: The URL of a custom pronunciation lexicon. Applies to + ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype custom_lexicon_url: str + :ivar custom_text_normalization_url: The URL of a custom text-normalization configuration. + Applies to ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype custom_text_normalization_url: str + :ivar prefer_locales: Preferred BCP-47 locales for multilingual synthesis. Applies to + ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype prefer_locales: list[str] + :ivar style: The voice speaking style. Applies only when ``voice_type`` is ``azure-standard``. + :vartype style: str + :ivar pitch: The voice pitch adjustment. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``. + :vartype pitch: str + :ivar volume: The voice volume adjustment. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``. + :vartype volume: str + :ivar custom_voice_endpoint_id: The Azure custom-voice deployment endpoint identifier. Applies + only when ``voice_type`` is ``azure-custom``. + :vartype custom_voice_endpoint_id: str + :ivar personal_voice_model: The Azure personal or avatar voice model. Applies only when + ``voice_type`` is ``azure-personal`` or ``avatar-voice-sync``. + :vartype personal_voice_model: str """ - type: Literal[ToolChoiceParamType.FILE_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. FILE_SEARCH.""" + voice: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice name or identifier. Applies to ``openai``, ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``azure-realtime-native``. It does not apply to ``avatar-voice-sync``, + which derives the voice name from the avatar.""" + voice_type: Optional[Union[str, "_models.VoiceType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The voice implementation. Known values are: \"openai\", \"azure-standard\", \"azure-custom\", + \"azure-personal\", \"avatar-voice-sync\", and \"azure-realtime-native\".""" + voice_locale: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The enforced BCP-47 output locale. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``.""" + speed: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The numeric output speed multiplier. Applies to all known ``voice_type`` values and defaults to + 1.""" + voice_temperature: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice variation temperature. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``.""" + custom_lexicon_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The URL of a custom pronunciation lexicon. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``.""" + custom_text_normalization_url: Optional[str] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The URL of a custom text-normalization configuration. Applies to ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``.""" + prefer_locales: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Preferred BCP-47 locales for multilingual synthesis. Applies to ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``.""" + style: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice speaking style. Applies only when ``voice_type`` is ``azure-standard``.""" + pitch: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice pitch adjustment. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``.""" + volume: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice volume adjustment. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``.""" + custom_voice_endpoint_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Azure custom-voice deployment endpoint identifier. Applies only when ``voice_type`` is + ``azure-custom``.""" + personal_voice_model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Azure personal or avatar voice model. Applies only when ``voice_type`` is + ``azure-personal`` or ``avatar-voice-sync``.""" @overload def __init__( self, + *, + voice: Optional[str] = None, + voice_type: Optional[Union[str, "_models.VoiceType"]] = None, + voice_locale: Optional[str] = None, + speed: Optional[float] = None, + voice_temperature: Optional[float] = None, + custom_lexicon_url: Optional[str] = None, + custom_text_normalization_url: Optional[str] = None, + prefer_locales: Optional[list[str]] = None, + style: Optional[str] = None, + pitch: Optional[str] = None, + volume: Optional[str] = None, + custom_voice_endpoint_id: Optional[str] = None, + personal_voice_model: Optional[str] = None, ) -> None: ... @overload @@ -26323,30 +35695,89 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.FILE_SEARCH # type: ignore -class ToolChoiceFunction( - ToolChoiceParam, discriminator="function" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Function tool. +class VoiceAgentAudioOutputConfig(VoiceAgentVoiceConfig): # pylint: disable=docstring-keyword-should-match-keyword-only + """Output audio configuration for a voice agent. Extends the voice configuration with the + session-level ``format`` and ``output_audio_timestamp_types`` settings, which apply to every + voice type. - :ivar type: For function calling, the type is 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 voice: The voice name or identifier. Applies to ``openai``, ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``azure-realtime-native``. It does not apply to + ``avatar-voice-sync``, which derives the voice name from the avatar. + :vartype voice: str + :ivar voice_type: The voice implementation. Known values are: "openai", "azure-standard", + "azure-custom", "azure-personal", "avatar-voice-sync", and "azure-realtime-native". + :vartype voice_type: str or ~azure.ai.projects.models.VoiceType + :ivar voice_locale: The enforced BCP-47 output locale. Applies to ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype voice_locale: str + :ivar speed: The numeric output speed multiplier. Applies to all known ``voice_type`` values + and defaults to 1. + :vartype speed: float + :ivar voice_temperature: The voice variation temperature. Applies to ``azure-standard``, + ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype voice_temperature: float + :ivar custom_lexicon_url: The URL of a custom pronunciation lexicon. Applies to + ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype custom_lexicon_url: str + :ivar custom_text_normalization_url: The URL of a custom text-normalization configuration. + Applies to ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype custom_text_normalization_url: str + :ivar prefer_locales: Preferred BCP-47 locales for multilingual synthesis. Applies to + ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. + :vartype prefer_locales: list[str] + :ivar style: The voice speaking style. Applies only when ``voice_type`` is ``azure-standard``. + :vartype style: str + :ivar pitch: The voice pitch adjustment. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``. + :vartype pitch: str + :ivar volume: The voice volume adjustment. Applies to ``azure-standard``, ``azure-custom``, + ``azure-personal``, and ``avatar-voice-sync``. + :vartype volume: str + :ivar custom_voice_endpoint_id: The Azure custom-voice deployment endpoint identifier. Applies + only when ``voice_type`` is ``azure-custom``. + :vartype custom_voice_endpoint_id: str + :ivar personal_voice_model: The Azure personal or avatar voice model. Applies only when + ``voice_type`` is ``azure-personal`` or ``avatar-voice-sync``. + :vartype personal_voice_model: str + :ivar format: The output audio format. Applies to every ``voice_type`` and defaults to 24 kHz + PCM. + :vartype format: ~azure.ai.projects.models.RealtimeAudioFormats + :ivar output_audio_timestamp_types: Timestamp kinds to include with output audio. Applies to + every ``voice_type``. + :vartype output_audio_timestamp_types: list[str or + ~azure.ai.projects.models.VoiceAgentAudioTimestampType] """ - type: Literal[ToolChoiceParamType.FUNCTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """For function calling, the type is always ``function``. Required. FUNCTION.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the function to call. Required.""" + format: Optional["_models.RealtimeAudioFormats"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The output audio format. Applies to every ``voice_type`` and defaults to 24 kHz PCM.""" + output_audio_timestamp_types: Optional[list[Union[str, "_models.VoiceAgentAudioTimestampType"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Timestamp kinds to include with output audio. Applies to every ``voice_type``.""" @overload def __init__( self, *, - name: str, + voice: Optional[str] = None, + voice_type: Optional[Union[str, "_models.VoiceType"]] = None, + voice_locale: Optional[str] = None, + speed: Optional[float] = None, + voice_temperature: Optional[float] = None, + custom_lexicon_url: Optional[str] = None, + custom_text_normalization_url: Optional[str] = None, + prefer_locales: Optional[list[str]] = None, + style: Optional[str] = None, + pitch: Optional[str] = None, + volume: Optional[str] = None, + custom_voice_endpoint_id: Optional[str] = None, + personal_voice_model: Optional[str] = None, + format: Optional["_models.RealtimeAudioFormats"] = None, + output_audio_timestamp_types: Optional[list[Union[str, "_models.VoiceAgentAudioTimestampType"]]] = None, ) -> None: ... @overload @@ -26358,23 +35789,74 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.FUNCTION # type: ignore -class ToolChoiceImageGeneration(ToolChoiceParam, discriminator="image_generation"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VoiceAgentAvatarConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Avatar configuration for a voice agent. These values are session defaults and may be overridden + when connecting. - :ivar type: Required. IMAGE_GENERATION. - :vartype type: str or ~azure.ai.projects.models.IMAGE_GENERATION + :ivar type: The avatar type. Required. Known values are: "video_avatar" and "photo_avatar". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentAvatarType + :ivar character: The avatar character identifier, e.g. 'lisa'. Required. + :vartype character: str + :ivar style: The avatar style, e.g. 'casual-sitting'. + :vartype style: str + :ivar customized: Whether the avatar is a customer-customized avatar. Defaults to false. + :vartype customized: bool + :ivar output_protocol: The transport used to deliver the avatar video stream. Known values are: + "webrtc" and "websocket". + :vartype output_protocol: str or ~azure.ai.projects.models.VoiceAgentAvatarOutputProtocol + :ivar model: The avatar model identifier. + :vartype model: str + :ivar video: Avatar video encoder and presentation settings. + :vartype video: ~azure.ai.projects.models.VoiceAgentAvatarVideoParams + :ivar scene: Avatar placement and motion settings. + :vartype scene: ~azure.ai.projects.models.VoiceAgentAvatarScene + :ivar output_audit_audio: Whether audit audio is emitted with avatar output. Defaults to false. + :vartype output_audit_audio: bool """ - type: Literal[ToolChoiceParamType.IMAGE_GENERATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. IMAGE_GENERATION.""" + type: Union[str, "_models.VoiceAgentAvatarType"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The avatar type. Required. Known values are: \"video_avatar\" and \"photo_avatar\".""" + character: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The avatar character identifier, e.g. 'lisa'. Required.""" + style: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The avatar style, e.g. 'casual-sitting'.""" + customized: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the avatar is a customer-customized avatar. Defaults to false.""" + output_protocol: Optional[Union[str, "_models.VoiceAgentAvatarOutputProtocol"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The transport used to deliver the avatar video stream. Known values are: \"webrtc\" and + \"websocket\".""" + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The avatar model identifier.""" + video: Optional["_models.VoiceAgentAvatarVideoParams"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Avatar video encoder and presentation settings.""" + scene: Optional["_models.VoiceAgentAvatarScene"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Avatar placement and motion settings.""" + output_audit_audio: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether audit audio is emitted with avatar output. Defaults to false.""" @overload def __init__( self, + *, + type: Union[str, "_models.VoiceAgentAvatarType"], + character: str, + style: Optional[str] = None, + customized: Optional[bool] = None, + output_protocol: Optional[Union[str, "_models.VoiceAgentAvatarOutputProtocol"]] = None, + model: Optional[str] = None, + video: Optional["_models.VoiceAgentAvatarVideoParams"] = None, + scene: Optional["_models.VoiceAgentAvatarScene"] = None, + output_audit_audio: Optional[bool] = None, ) -> None: ... @overload @@ -26386,34 +35868,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.IMAGE_GENERATION # type: ignore -class ToolChoiceMCP( - ToolChoiceParam, discriminator="mcp" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """MCP tool. +class VoiceAgentAvatarIceServer(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """An ICE server used for avatar WebRTC negotiation. - :ivar type: For MCP tools, the type is always ``mcp``. Required. MCP. - :vartype type: str or ~azure.ai.projects.models.MCP - :ivar server_label: The label of the MCP server to use. Required. - :vartype server_label: str - :ivar name: - :vartype name: str + :ivar urls: Required. + :vartype urls: list[str] + :ivar username: + :vartype username: str + :ivar credential: + :vartype credential: str """ - type: Literal[ToolChoiceParamType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """For MCP tools, the type is always ``mcp``. Required. MCP.""" - server_label: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The label of the MCP server to use. Required.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + urls: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + username: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + credential: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - server_label: str, - name: Optional[str] = None, + urls: list[str], + username: Optional[str] = None, + credential: Optional[str] = None, ) -> None: ... @overload @@ -26425,23 +35904,46 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.MCP # type: ignore -class ToolChoiceWebSearchPreview(ToolChoiceParam, discriminator="web_search_preview"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VoiceAgentAvatarScene(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Avatar placement and motion settings. - :ivar type: Required. WEB_SEARCH_PREVIEW. - :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW + :ivar zoom: + :vartype zoom: float + :ivar position_x: + :vartype position_x: float + :ivar position_y: + :vartype position_y: float + :ivar rotation_x: + :vartype rotation_x: float + :ivar rotation_y: + :vartype rotation_y: float + :ivar rotation_z: + :vartype rotation_z: float + :ivar amplitude: + :vartype amplitude: float """ - type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. WEB_SEARCH_PREVIEW.""" + zoom: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + position_x: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + position_y: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + rotation_x: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + rotation_y: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + rotation_z: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + amplitude: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, + *, + zoom: Optional[float] = None, + position_x: Optional[float] = None, + position_y: Optional[float] = None, + rotation_x: Optional[float] = None, + rotation_y: Optional[float] = None, + rotation_z: Optional[float] = None, + amplitude: Optional[float] = None, ) -> None: ... @overload @@ -26453,23 +35955,26 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW # type: ignore -class ToolChoiceWebSearchPreview20250311(ToolChoiceParam, discriminator="web_search_preview_2025_03_11"): - """Indicates that the model should use a built-in tool to generate a response. `Learn more about - built-in tools `_. +class VoiceAgentAvatarVideoBackground(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The avatar video background. - :ivar type: Required. WEB_SEARCH_PREVIEW_2025_03_11. - :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW_2025_03_11 + :ivar image_url: + :vartype image_url: str + :ivar color: + :vartype color: str """ - type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. WEB_SEARCH_PREVIEW_2025_03_11.""" + image_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + color: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, + *, + image_url: Optional[str] = None, + color: Optional[str] = None, ) -> None: ... @overload @@ -26481,35 +35986,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11 # type: ignore -class ToolConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Per-tool configuration that controls tool visibility and search behavior. +class VoiceAgentAvatarVideoCrop(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The rectangular crop applied to avatar video. - :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 + :ivar bottom_right: Required. + :vartype bottom_right: list[int] + :ivar top_left: Required. + :vartype top_left: list[int] """ - 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.""" + bottom_right: list[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + top_left: list[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - pin: Optional[bool] = None, - additional_search_text: Optional[str] = None, + bottom_right: list[int], + top_left: list[int], ) -> None: ... @overload @@ -26523,26 +36021,43 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolDescription(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Description of a tool that can be used by an agent. +class VoiceAgentAvatarVideoParams(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Avatar video encoder and presentation settings. - :ivar name: The name of the tool. - :vartype name: str - :ivar description: A brief description of the tool's purpose. - :vartype description: str + :ivar bitrate: The target video bitrate in bits per second. + :vartype bitrate: int + :ivar crop: + :vartype crop: ~azure.ai.projects.models.VoiceAgentAvatarVideoCrop + :ivar resolution: + :vartype resolution: ~azure.ai.projects.models.VoiceAgentAvatarVideoResolution + :ivar background: + :vartype background: ~azure.ai.projects.models.VoiceAgentAvatarVideoBackground + :ivar gop_size: + :vartype gop_size: int """ - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the tool.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A brief description of the tool's purpose.""" + bitrate: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target video bitrate in bits per second.""" + crop: Optional["_models.VoiceAgentAvatarVideoCrop"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + resolution: Optional["_models.VoiceAgentAvatarVideoResolution"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + background: Optional["_models.VoiceAgentAvatarVideoBackground"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + gop_size: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @overload def __init__( self, *, - name: Optional[str] = None, - description: Optional[str] = None, + bitrate: Optional[int] = None, + crop: Optional["_models.VoiceAgentAvatarVideoCrop"] = None, + resolution: Optional["_models.VoiceAgentAvatarVideoResolution"] = None, + background: Optional["_models.VoiceAgentAvatarVideoBackground"] = None, + gop_size: Optional[int] = None, ) -> None: ... @overload @@ -26556,22 +36071,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolProjectConnection(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A project connection resource. +class VoiceAgentAvatarVideoResolution(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The avatar video resolution. - :ivar project_connection_id: A project connection in a ToolProjectConnectionList attached to - this tool. Required. - :vartype project_connection_id: str + :ivar width: Required. + :vartype width: int + :ivar height: Required. + :vartype height: int """ - project_connection_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A project connection in a ToolProjectConnectionList attached to this tool. Required.""" + width: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + height: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - project_connection_id: str, + width: int, + height: int, ) -> None: ... @overload @@ -26585,33 +36104,36 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolSearchToolboxTool( - ToolboxTool, discriminator="toolbox_search" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A toolbox search tool stored in a toolbox. +class VoiceAgentTurnDetectionConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Turn-detection configuration for a voice agent. - :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 type: The type of the tool. Always ``toolbox_search``. Required. TOOLBOX_SEARCH. - :vartype type: str or ~azure.ai.projects.models.TOOLBOX_SEARCH + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentAzureSemanticVadTurnDetection, VoiceAgentAzureSemanticVadEnTurnDetection, + VoiceAgentAzureSemanticVadMultilingualTurnDetection, VoiceAgentSemanticVadTurnDetection, + VoiceAgentServerVadTurnDetection + + :ivar type: The turn-detection strategy. Required. Known values are: "server_vad", + "semantic_vad", "azure_semantic_vad", "azure_semantic_vad_en", and + "azure_semantic_vad_multilingual". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentTurnDetectionType + :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech + stops. + :vartype auto_truncate: bool """ - type: Literal[ToolboxToolType.TOOLBOX_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``toolbox_search``. Required. TOOLBOX_SEARCH.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The turn-detection strategy. Required. Known values are: \"server_vad\", \"semantic_vad\", + \"azure_semantic_vad\", \"azure_semantic_vad_en\", and \"azure_semantic_vad_multilingual\".""" + auto_truncate: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the input audio buffer is truncated automatically when speech stops.""" @overload def __init__( self, *, - name: Optional[str] = None, - description: Optional[str] = None, - tool_configs: Optional[dict[str, "_models.ToolConfig"]] = None, + type: str, + auto_truncate: Optional[bool] = None, ) -> None: ... @overload @@ -26623,44 +36145,86 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolboxToolType.TOOLBOX_SEARCH # type: ignore -class ToolSearchToolParam( - Tool, discriminator="tool_search" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Tool search tool. +class VoiceAgentAzureSemanticVadEnTurnDetection( + VoiceAgentTurnDetectionConfig, discriminator="azure_semantic_vad_en" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """English-optimized Azure semantic voice activity detection. - :ivar type: The type of the tool. Always ``tool_search``. Required. TOOL_SEARCH. - :vartype type: str or ~azure.ai.projects.models.TOOL_SEARCH - :ivar execution: Whether tool search is executed by the server or by the client. Known values - are: "server" and "client". - :vartype execution: str or ~azure.ai.projects.models.ToolSearchExecutionType - :ivar description: - :vartype description: str - :ivar parameters: - :vartype parameters: ~azure.ai.projects.models.EmptyModelParam + :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech + stops. + :vartype auto_truncate: bool + :ivar type: Required. English-optimized Azure semantic voice activity detection. + :vartype type: str or ~azure.ai.projects.models.AZURE_SEMANTIC_VAD_EN + :ivar threshold: Activation threshold for voice activity detection, from 0 to 1. + :vartype threshold: float + :ivar prefix_padding_ms: Audio to include before detected speech, in milliseconds. + :vartype prefix_padding_ms: ~datetime.timedelta + :ivar silence_duration_ms: Silence required to end speech detection, in milliseconds. + :vartype silence_duration_ms: ~datetime.timedelta + :ivar idle_timeout_ms: Maximum idle time before the detector ends the turn, in milliseconds. + :vartype idle_timeout_ms: ~datetime.timedelta + :ivar end_of_utterance_detection: Semantic end-of-utterance detection configuration. Set to + null to disable it. + :vartype end_of_utterance_detection: + ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection + :ivar speech_duration_ms: Minimum speech duration required to trigger detection, in + milliseconds. + :vartype speech_duration_ms: ~datetime.timedelta + :ivar remove_filler_words: Whether filler words are removed from transcription. + :vartype remove_filler_words: bool + :ivar create_response: Whether a response is created automatically when speech stops. + :vartype create_response: bool + :ivar interrupt_response: Whether user speech may interrupt the agent's response. + :vartype interrupt_response: bool """ - type: Literal[ToolType.TOOL_SEARCH] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``tool_search``. Required. TOOL_SEARCH.""" - execution: Optional[Union[str, "_models.ToolSearchExecutionType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_EN] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. English-optimized Azure semantic voice activity detection.""" + threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Activation threshold for voice activity detection, from 0 to 1.""" + prefix_padding_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" ) - """Whether tool search is executed by the server or by the client. Known values are: \"server\" - and \"client\".""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - parameters: Optional["_models.EmptyModelParam"] = rest_field( + """Audio to include before detected speech, in milliseconds.""" + silence_duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Silence required to end speech detection, in milliseconds.""" + idle_timeout_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Maximum idle time before the detector ends the turn, in milliseconds.""" + end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) + """Semantic end-of-utterance detection configuration. Set to null to disable it.""" + speech_duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Minimum speech duration required to trigger detection, in milliseconds.""" + remove_filler_words: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether filler words are removed from transcription.""" + create_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether a response is created automatically when speech stops.""" + interrupt_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether user speech may interrupt the agent's response.""" @overload def __init__( self, *, - execution: Optional[Union[str, "_models.ToolSearchExecutionType"]] = None, - description: Optional[str] = None, - parameters: Optional["_models.EmptyModelParam"] = None, + auto_truncate: Optional[bool] = None, + threshold: Optional[float] = None, + prefix_padding_ms: Optional[datetime.timedelta] = None, + silence_duration_ms: Optional[datetime.timedelta] = None, + idle_timeout_ms: Optional[datetime.timedelta] = None, + end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = None, + speech_duration_ms: Optional[datetime.timedelta] = None, + remove_filler_words: Optional[bool] = None, + create_response: Optional[bool] = None, + interrupt_response: Optional[bool] = None, ) -> None: ... @overload @@ -26672,41 +36236,92 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolType.TOOL_SEARCH # type: ignore + self.type = VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_EN # type: ignore -class ToolUseFineTuningDataGenerationJobConfiguration( - DataGenerationJobConfiguration, discriminator="tool_use" +class VoiceAgentAzureSemanticVadMultilingualTurnDetection( + VoiceAgentTurnDetectionConfig, discriminator="azure_semantic_vad_multilingual" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """The configuration for a data generation job with ToolUse type. This is a preview feature used - only for fine-tuning scenarios. + """Multilingual Azure semantic voice activity detection. - :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 - :ivar max_samples: Maximum number of samples to generate, up to service-defined limits. - Required. - :vartype max_samples: int + :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech + stops. + :vartype auto_truncate: bool + :ivar type: Required. Multilingual Azure semantic voice activity detection. + :vartype type: str or ~azure.ai.projects.models.AZURE_SEMANTIC_VAD_MULTILINGUAL + :ivar threshold: Activation threshold for voice activity detection, from 0 to 1. + :vartype threshold: float + :ivar prefix_padding_ms: Audio to include before detected speech, in milliseconds. + :vartype prefix_padding_ms: ~datetime.timedelta + :ivar silence_duration_ms: Silence required to end speech detection, in milliseconds. + :vartype silence_duration_ms: ~datetime.timedelta + :ivar idle_timeout_ms: Maximum idle time before the detector ends the turn, in milliseconds. + :vartype idle_timeout_ms: ~datetime.timedelta + :ivar end_of_utterance_detection: Semantic end-of-utterance detection configuration. Set to + null to disable it. + :vartype end_of_utterance_detection: + ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection + :ivar speech_duration_ms: Minimum speech duration required to trigger detection, in + milliseconds. + :vartype speech_duration_ms: ~datetime.timedelta + :ivar remove_filler_words: Whether filler words are removed from transcription. + :vartype remove_filler_words: bool + :ivar create_response: Whether a response is created automatically when speech stops. + :vartype create_response: bool + :ivar interrupt_response: Whether user speech may interrupt the agent's response. + :vartype interrupt_response: bool + :ivar languages: BCP-47 language codes used for speech detection. + :vartype languages: list[str] """ - 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.""" - max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of samples to generate, up to service-defined limits. Required.""" + type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_MULTILINGUAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Multilingual Azure semantic voice activity detection.""" + threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Activation threshold for voice activity detection, from 0 to 1.""" + prefix_padding_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Audio to include before detected speech, in milliseconds.""" + silence_duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Silence required to end speech detection, in milliseconds.""" + idle_timeout_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Maximum idle time before the detector ends the turn, in milliseconds.""" + end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Semantic end-of-utterance detection configuration. Set to null to disable it.""" + speech_duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Minimum speech duration required to trigger detection, in milliseconds.""" + remove_filler_words: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether filler words are removed from transcription.""" + create_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether a response is created automatically when speech stops.""" + interrupt_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether user speech may interrupt the agent's response.""" + languages: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """BCP-47 language codes used for speech detection.""" @overload def __init__( self, *, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, + auto_truncate: Optional[bool] = None, + threshold: Optional[float] = None, + prefix_padding_ms: Optional[datetime.timedelta] = None, + silence_duration_ms: Optional[datetime.timedelta] = None, + idle_timeout_ms: Optional[datetime.timedelta] = None, + end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = None, + speech_duration_ms: Optional[datetime.timedelta] = None, + remove_filler_words: Optional[bool] = None, + create_response: Optional[bool] = None, + interrupt_response: Optional[bool] = None, + languages: Optional[list[str]] = None, ) -> None: ... @overload @@ -26718,126 +36333,161 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobType.TOOL_USE # type: ignore + self.type = VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_MULTILINGUAL # type: ignore -class TracesDataGenerationJobConfiguration( - DataGenerationJobConfiguration, discriminator="traces" +class VoiceAgentAzureSemanticVadTurnDetection( + VoiceAgentTurnDetectionConfig, discriminator="azure_semantic_vad" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """The configuration for a data generation job with Traces type. + """Azure semantic voice activity detection. - :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 - :ivar max_samples: Maximum number of samples to generate, up to service-defined limits. If - omitted, sampling is turned off. - :vartype max_samples: int - :ivar redact_private_content: Whether to redact private content from traces. When omitted or - set to true, private content is redacted. Set to false to opt out of redaction. - :vartype redact_private_content: bool + :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech + stops. + :vartype auto_truncate: bool + :ivar type: Required. Azure semantic voice activity detection. + :vartype type: str or ~azure.ai.projects.models.AZURE_SEMANTIC_VAD + :ivar threshold: Activation threshold for voice activity detection, from 0 to 1. + :vartype threshold: float + :ivar prefix_padding_ms: Audio to include before detected speech, in milliseconds. + :vartype prefix_padding_ms: ~datetime.timedelta + :ivar silence_duration_ms: Silence required to end speech detection, in milliseconds. + :vartype silence_duration_ms: ~datetime.timedelta + :ivar idle_timeout_ms: Maximum idle time before the detector ends the turn, in milliseconds. + :vartype idle_timeout_ms: ~datetime.timedelta + :ivar end_of_utterance_detection: Semantic end-of-utterance detection configuration. Set to + null to disable it. + :vartype end_of_utterance_detection: + ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection + :ivar speech_duration_ms: Minimum speech duration required to trigger detection, in + milliseconds. + :vartype speech_duration_ms: ~datetime.timedelta + :ivar remove_filler_words: Whether filler words are removed from transcription. + :vartype remove_filler_words: bool + :ivar create_response: Whether a response is created automatically when speech stops. + :vartype create_response: bool + :ivar interrupt_response: Whether user speech may interrupt the agent's response. + :vartype interrupt_response: bool + :ivar languages: BCP-47 language codes used for speech detection. + :vartype languages: list[str] """ - 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.""" - max_samples: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of samples to generate, up to service-defined limits. If omitted, sampling is - turned off.""" - redact_private_content: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether to redact private content from traces. When omitted or set to true, private content is - redacted. Set to false to opt out of redaction.""" + type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Azure semantic voice activity detection.""" + threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Activation threshold for voice activity detection, from 0 to 1.""" + prefix_padding_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Audio to include before detected speech, in milliseconds.""" + silence_duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Silence required to end speech detection, in milliseconds.""" + idle_timeout_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Maximum idle time before the detector ends the turn, in milliseconds.""" + end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Semantic end-of-utterance detection configuration. Set to null to disable it.""" + speech_duration_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Minimum speech duration required to trigger detection, in milliseconds.""" + remove_filler_words: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether filler words are removed from transcription.""" + create_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether a response is created automatically when speech stops.""" + interrupt_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether user speech may interrupt the agent's response.""" + languages: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """BCP-47 language codes used for speech detection.""" @overload def __init__( self, *, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, - max_samples: Optional[int] = None, - redact_private_content: Optional[bool] = None, + auto_truncate: Optional[bool] = None, + threshold: Optional[float] = None, + prefix_padding_ms: Optional[datetime.timedelta] = None, + silence_duration_ms: Optional[datetime.timedelta] = None, + idle_timeout_ms: Optional[datetime.timedelta] = None, + end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = None, + speech_duration_ms: Optional[datetime.timedelta] = None, + remove_filler_words: Optional[bool] = None, + create_response: Optional[bool] = None, + interrupt_response: Optional[bool] = None, + languages: 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) - self.type = DataGenerationJobType.TRACES # type: ignore - - -class TracesDataGenerationJobSource( - DataGenerationJobSource, discriminator="traces" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """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 - :ivar trace_ids: Optional explicit list of trace IDs to include. - :vartype trace_ids: list[str] + """ + :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 = VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD # type: ignore + + +class VoiceAgentBaseDefinition( + AgentDefinition, discriminator="voice" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Shared voice-agent settings; protocol-specific fields remain flat on each subtype. Creates and + updates produce immutable versions. Each version selects its own protocol, so a new version can + switch between Realtime and Live. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentLiveDefinition, VoiceAgentDefinition + + :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. + :vartype rai_config: ~azure.ai.projects.models.RaiConfig + :ivar kind: Always voice. Required. VOICE. + :vartype kind: str or ~azure.ai.projects.models.VOICE + :ivar sub_protocol: The voice protocol for this agent version. Null and unknown values are + invalid. Required. Known values are: "realtime" and "live". + :vartype sub_protocol: str or ~azure.ai.projects.models.VoiceAgentSubProtocol + :ivar instructions: Frontend instructions, templated with structured_inputs. Backend + instructions belong in delegation.responses. + :vartype instructions: str + :ivar structured_inputs: Template inputs for session instructions and supported greetings. + :vartype structured_inputs: dict[str, ~azure.ai.projects.models.StructuredInputDefinition] + :ivar store: Persists conversation content and audio in Foundry, not native Live recordings. + Defaults to false. + :vartype store: bool """ - 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" + __mapping__: dict[str, _Model] = {} + kind: Literal[AgentKind.VOICE] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Always voice. Required. VOICE.""" + sub_protocol: str = rest_discriminator( + name="sub_protocol", visibility=["read", "create", "update", "delete", "query"] ) - """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" + """The voice protocol for this agent version. Null and unknown values are invalid. Required. Known + values are: \"realtime\" and \"live\".""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Frontend instructions, templated with structured_inputs. Backend instructions belong in + delegation.responses.""" + structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """End of the time window (Unix timestamp in seconds). Defaults to current time.""" - trace_ids: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional explicit list of trace IDs to include.""" + """Template inputs for session instructions and supported greetings.""" + store: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Persists conversation content and audio in Foundry, not native Live recordings. Defaults to + false.""" @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, - trace_ids: Optional[list[str]] = None, + sub_protocol: str, + rai_config: Optional["_models.RaiConfig"] = None, + instructions: Optional[str] = None, + structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = None, + store: Optional[bool] = None, ) -> None: ... @overload @@ -26849,71 +36499,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobSourceType.TRACES # type: ignore + self.kind = AgentKind.VOICE # type: ignore -class TracesEvaluatorGenerationJobSource( - EvaluatorGenerationJobSource, discriminator="traces" +class VoiceAgentClientEventRtcCallSdpCreate( + RealtimeClientEvent, discriminator="rtc.call.sdp.create" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Traces source for evaluator generation jobs — conversation traces from Application Insights. + """The ``rtc.call.sdp.create`` client event: begins WebRTC signaling with an SDP offer. - :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 + :ivar type: The event type. Always ``rtc.call.sdp.create``. Required. RTC_CALL_SDP_CREATE. + :vartype type: str or ~azure.ai.projects.models.RTC_CALL_SDP_CREATE + :ivar event_id: An optional client-generated event identifier. + :vartype event_id: str + :ivar sdp_offer: The client's SDP offer for the WebRTC connection. Required. + :vartype sdp_offer: str + :ivar session: Optional session configuration. For an ``/agents`` endpoint the service rebuilds + it authoritatively from the persisted agent definition. + :vartype session: ~azure.ai.projects.models.VoiceAgentSessionUpdateConfig """ - 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" + type: Literal[VoiceAgentClientEventTypeExtension.RTC_CALL_SDP_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``rtc.call.sdp.create``. Required. RTC_CALL_SDP_CREATE.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional client-generated event identifier.""" + sdp_offer: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The client's SDP offer for the WebRTC connection. Required.""" + session: Optional["_models.VoiceAgentSessionUpdateConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """End of the time window (Unix timestamp in seconds). Defaults to current time.""" + """Optional session configuration. For an ``/agents`` endpoint the service rebuilds it + authoritatively from the persisted agent definition.""" @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, + sdp_offer: str, + event_id: Optional[str] = None, + session: Optional["_models.VoiceAgentSessionUpdateConfig"] = None, ) -> None: ... @overload @@ -26925,24 +36548,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorGenerationJobSourceType.TRACES # type: ignore + self.type = VoiceAgentClientEventTypeExtension.RTC_CALL_SDP_CREATE # type: ignore -class TranscriptionLanguage(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A language detected in transcribed audio. +class VoiceAgentClientEventSessionAvatarConnect( + RealtimeClientEvent, discriminator="session.avatar.connect" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The ``session.avatar.connect`` client event. - :ivar code: The code of a language detected in the audio. Required. - :vartype code: str + :ivar type: The event type. Always ``session.avatar.connect``. Required. + SESSION_AVATAR_CONNECT. + :vartype type: str or ~azure.ai.projects.models.SESSION_AVATAR_CONNECT + :ivar event_id: An optional client-generated event identifier. + :vartype event_id: str + :ivar client_sdp: The client's SDP offer for avatar media negotiation. Required. + :vartype client_sdp: str """ - code: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The code of a language detected in the audio. Required.""" + type: Literal[VoiceAgentClientEventTypeExtension.SESSION_AVATAR_CONNECT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``session.avatar.connect``. Required. SESSION_AVATAR_CONNECT.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional client-generated event identifier.""" + client_sdp: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The client's SDP offer for avatar media negotiation. Required.""" @overload def __init__( self, *, - code: str, + client_sdp: str, + event_id: Optional[str] = None, ) -> None: ... @overload @@ -26954,32 +36589,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = VoiceAgentClientEventTypeExtension.SESSION_AVATAR_CONNECT # type: ignore -class TranscriptTextUsageDuration( - CreateTranscriptionResponseJsonUsage, discriminator="duration" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Duration Usage. +class VoiceAgentClientEventSessionUpdate(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The ``session.update`` client event. - :ivar type: The type of the usage object. Always ``duration`` for this variant. Required. - DURATION. - :vartype type: str or ~azure.ai.projects.models.DURATION - :ivar seconds: Duration of the input audio in seconds. Required. - :vartype seconds: ~datetime.timedelta + :ivar event_id: Optional client-generated ID used to identify this event. This is an arbitrary + string that a client may assign. It will be passed back if there is an error with the event, + but the corresponding ``session.updated`` event will not include it. + :vartype event_id: str + :ivar type: The event type, must be ``session.update``. Required. SESSION_UPDATE. + :vartype type: str or ~azure.ai.projects.models.SESSION_UPDATE + :ivar session: The voice-agent session settings to update. Required. Is one of the following + types: VoiceAgentSessionUpdateConfig + :vartype session: ~azure.ai.projects.models.VoiceAgentSessionUpdateConfig """ - type: Literal[CreateTranscriptionResponseJsonUsageType.DURATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the usage object. Always ``duration`` for this variant. Required. DURATION.""" - seconds: datetime.timedelta = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional client-generated ID used to identify this event. This is an arbitrary string that a + client may assign. It will be passed back if there is an error with the event, but the + corresponding ``session.updated`` event will not include it.""" + type: Literal[RealtimeClientEventType.SESSION_UPDATE] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Duration of the input audio in seconds. Required.""" + """The event type, must be ``session.update``. Required. SESSION_UPDATE.""" + session: "_unions.VoiceAgentSessionUpdate" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The voice-agent session settings to update. Required. Is one of the following types: + VoiceAgentSessionUpdateConfig""" @overload def __init__( self, *, - seconds: datetime.timedelta, + type: Literal[RealtimeClientEventType.SESSION_UPDATE], + session: "_unions.VoiceAgentSessionUpdate", + event_id: Optional[str] = None, ) -> None: ... @overload @@ -26991,48 +36636,62 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = CreateTranscriptionResponseJsonUsageType.DURATION # type: ignore -class TranscriptTextUsageTokens( - CreateTranscriptionResponseJsonUsage, discriminator="tokens" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Token Usage. +class VoiceAgentCollectDtmfStartArguments(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Arguments for starting DTMF collection on a model call. - :ivar type: The type of the usage object. Always ``tokens`` for this variant. Required. TOKENS. - :vartype type: str or ~azure.ai.projects.models.TOKENS - :ivar input_tokens: Number of input tokens billed for this request. Required. - :vartype input_tokens: int - :ivar input_token_details: Details about the input tokens billed for this request. - :vartype input_token_details: - ~azure.ai.projects.models.TranscriptTextUsageTokensInputTokenDetails - :ivar output_tokens: Number of output tokens generated. Required. - :vartype output_tokens: int - :ivar total_tokens: Total number of tokens used (input + output). Required. - :vartype total_tokens: int + :ivar secret: Required; no default. True returns a private reference, false returns the value. + Privacy cannot be downgraded after collection starts. Required. + :vartype secret: bool + :ivar output_variable_name: Preferred bare name for the output variable, required for ``secret: + true`` and forbidden otherwise. + :vartype output_variable_name: str + :ivar timeout_seconds: Total deadline in seconds (1-300), including receiver setup. Overrides + the Agent timeout; if both are omitted, defaults to 60. Duplicate calls do not reset it. + :vartype timeout_seconds: int + :ivar completion_mode: Required typed object selecting one completion policy and its + parameters, not an array of simultaneous rules. Required. Is one of the following types: + VoiceAgentDtmfFixedLengthCompletionMode, VoiceAgentDtmfTerminatorCompletionMode, + VoiceAgentDtmfInterDigitSilenceCompletionMode + :vartype completion_mode: ~azure.ai.projects.models.VoiceAgentDtmfFixedLengthCompletionMode or + ~azure.ai.projects.models.VoiceAgentDtmfTerminatorCompletionMode or + ~azure.ai.projects.models.VoiceAgentDtmfInterDigitSilenceCompletionMode + :ivar first_digit_timeout_seconds: The maximum wait for the first digit in integer seconds, + starting at receiver readiness and bounded by the remaining total deadline. Omit for fifteen + seconds. + :vartype first_digit_timeout_seconds: int """ - type: Literal[CreateTranscriptionResponseJsonUsageType.TOKENS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the usage object. Always ``tokens`` for this variant. Required. TOKENS.""" - input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of input tokens billed for this request. Required.""" - input_token_details: Optional["_models.TranscriptTextUsageTokensInputTokenDetails"] = rest_field( + secret: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required; no default. True returns a private reference, false returns the value. Privacy cannot + be downgraded after collection starts. Required.""" + output_variable_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Preferred bare name for the output variable, required for ``secret: true`` and forbidden + otherwise.""" + timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total deadline in seconds (1-300), including receiver setup. Overrides the Agent timeout; if + both are omitted, defaults to 60. Duplicate calls do not reset it.""" + completion_mode: "_unions.VoiceAgentDtmfCompletionMode" = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Details about the input tokens billed for this request.""" - output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of output tokens generated. Required.""" - total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Total number of tokens used (input + output). Required.""" + """Required typed object selecting one completion policy and its parameters, not an array of + simultaneous rules. Required. Is one of the following types: + VoiceAgentDtmfFixedLengthCompletionMode, VoiceAgentDtmfTerminatorCompletionMode, + VoiceAgentDtmfInterDigitSilenceCompletionMode""" + first_digit_timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The maximum wait for the first digit in integer seconds, starting at receiver readiness and + bounded by the remaining total deadline. Omit for fifteen seconds.""" @overload def __init__( self, *, - input_tokens: int, - output_tokens: int, - total_tokens: int, - input_token_details: Optional["_models.TranscriptTextUsageTokensInputTokenDetails"] = None, + secret: bool, + completion_mode: "_unions.VoiceAgentDtmfCompletionMode", + output_variable_name: Optional[str] = None, + timeout_seconds: Optional[int] = None, + first_digit_timeout_seconds: Optional[int] = None, ) -> None: ... @overload @@ -27044,29 +36703,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = CreateTranscriptionResponseJsonUsageType.TOKENS # type: ignore -class TranscriptTextUsageTokensInputTokenDetails( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """TranscriptTextUsageTokensInputTokenDetails. +class VoiceAgentTool(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A tool usable by a voice agent. - :ivar text_tokens: - :vartype text_tokens: int - :ivar audio_tokens: - :vartype audio_tokens: int + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentFunctionTool, VoiceAgentMcpTool, VoiceAgentSystemTool, VoiceAgentToolboxTool + + :ivar type: The tool kind. Required. Known values are: "function", "mcp", "system", and + "toolbox". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentToolType """ - text_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - audio_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The tool kind. Required. Known values are: \"function\", \"mcp\", \"system\", and \"toolbox\".""" @overload def __init__( self, *, - text_tokens: Optional[int] = None, - audio_tokens: Optional[int] = None, + type: str, ) -> None: ... @overload @@ -27080,43 +36738,55 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TwilioTelephonyBinding( - TelephonyBinding, discriminator="twilio" +class VoiceAgentSystemTool( + VoiceAgentTool, discriminator="system" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A Twilio binding owned by a voice agent. + """A service-managed control that acts on the active voice session without customer code or + external authentication. - :ivar id: The service-generated binding identifier. Required. - :vartype id: str - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: The optional display label for the binding. - :vartype label: str - :ivar status: The lifecycle status. Required. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar incoming_call_url: The service-generated webhook URL to configure with the telephony - provider. Required. - :vartype incoming_call_url: str - :ivar provider: The Twilio provider. Required. Twilio Programmable Voice. - :vartype provider: str or ~azure.ai.projects.models.TWILIO - :ivar phone_number: The Twilio E.164 phone number. Required. - :vartype phone_number: str + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentCollectDtmfSystemTool, VoiceAgentCollectSmsSystemTool, + VoiceAgentDigitRecognitionSystemTool, VoiceAgentEndConversationSystemTool, + VoiceAgentLanguageDetectionSystemTool, VoiceAgentSendDtmfSystemTool, + VoiceAgentSendSmsSystemTool, VoiceAgentTransferSystemTool + + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar name: The service-managed control action. Known values are stable; additional values may + be added over time. Required. Known values are: "end_conversation", "language_detection", + "digit_recognition", "transfer", "collect_sms", "collect_dtmf", "send_dtmf", and "send_sms". + :vartype name: str or ~azure.ai.projects.models.VoiceAgentSystemToolName + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta """ - provider: Literal[TelephonyProvider.TWILIO] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Twilio provider. Required. Twilio Programmable Voice.""" - phone_number: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Twilio E.164 phone number. Required.""" + __mapping__: dict[str, _Model] = {} + type: Literal[VoiceAgentToolType.SYSTEM] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``system``. Required. A service-managed control that acts on the + active voice session.""" + name: str = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) + """The service-managed control action. Known values are stable; additional values may be added + over time. Required. Known values are: \"end_conversation\", \"language_detection\", + \"digit_recognition\", \"transfer\", \"collect_sms\", \"collect_dtmf\", \"send_dtmf\", and + \"send_sms\".""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional description of the system tool.""" + timeout_seconds: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + ) + """Execution timeout, from 1 to 300 seconds. If omitted, the service defaults to 60 seconds.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - connection_name: str, - status: Union[str, "_models.TelephonyBindingStatus"], - incoming_call_url: str, - phone_number: str, - label: Optional[str] = None, + name: str, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -27128,49 +36798,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.provider = TelephonyProvider.TWILIO # type: ignore + self.type = VoiceAgentToolType.SYSTEM # type: ignore -class TwilioTelephonyBindingListItem( - TelephonyBindingListItem, discriminator="twilio" +class VoiceAgentCollectDtmfSystemTool( + VoiceAgentSystemTool, discriminator="collect_dtmf" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A Twilio binding returned in a list, including its entity tag. + """Collects keypad digits on the current call. - :ivar id: The service-generated binding identifier. Required. - :vartype id: str - :ivar connection_name: The Foundry connection name for the telephony provider. Required. - :vartype connection_name: str - :ivar label: The optional display label for the binding. - :vartype label: str - :ivar status: The lifecycle status. Required. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar incoming_call_url: The service-generated webhook URL to configure with the telephony - provider. Required. - :vartype incoming_call_url: str - :ivar etag: The entity tag to send in the ``If-Match`` header when updating or deleting this - binding. Required. - :vartype etag: str - :ivar provider: The Twilio provider. Required. Twilio Programmable Voice. - :vartype provider: str or ~azure.ai.projects.models.TWILIO - :ivar phone_number: The Twilio E.164 phone number. Required. - :vartype phone_number: str + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``collect_dtmf``. Required. Collects + keypad digits on the current call. + :vartype name: str or ~azure.ai.projects.models.COLLECT_DTMF """ - provider: Literal[TelephonyProvider.TWILIO] = rest_discriminator(name="provider", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The Twilio provider. Required. Twilio Programmable Voice.""" - phone_number: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Twilio E.164 phone number. Required.""" + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.COLLECT_DTMF] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``collect_dtmf``. Required. Collects keypad digits + on the current call.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - connection_name: str, - status: Union[str, "_models.TelephonyBindingStatus"], - incoming_call_url: str, - phone_number: str, - label: Optional[str] = None, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -27182,29 +36841,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.provider = TelephonyProvider.TWILIO # type: ignore + self.name = VoiceAgentSystemToolName.COLLECT_DTMF # type: ignore -class UpdateModelVersionRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Request body for updating a model version. Only description and tags can be modified. +class VoiceAgentCollectionStartArguments(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Arguments for starting a collection on a model call. - :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 secret: Required; no default. True returns a private reference, false returns the value. + Privacy cannot be downgraded after collection starts. Required. + :vartype secret: bool + :ivar output_variable_name: Preferred bare name for the output variable, required for ``secret: + true`` and forbidden otherwise. + :vartype output_variable_name: str + :ivar timeout_seconds: Total deadline in seconds (1-300), including receiver setup. Overrides + the Agent timeout; if both are omitted, defaults to 60. Duplicate calls do not reset it. + :vartype timeout_seconds: int """ - 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.""" + secret: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required; no default. True returns a private reference, false returns the value. Privacy cannot + be downgraded after collection starts. Required.""" + output_variable_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Preferred bare name for the output variable, required for ``secret: true`` and forbidden + otherwise.""" + timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total deadline in seconds (1-300), including receiver setup. Overrides the Agent timeout; if + both are omitted, defaults to 60. Duplicate calls do not reset it.""" @overload def __init__( self, *, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + secret: bool, + output_variable_name: Optional[str] = None, + timeout_seconds: Optional[int] = None, ) -> None: ... @overload @@ -27218,46 +36888,45 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UpdateTelephonyBindingRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The request to update an existing telephony binding. Every property is optional and the - binding's provider is immutable. +class VoiceAgentCollectSmsStartArguments(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Model-call SMS collection arguments, validated before receiver setup. The model supplies the + sender, not the collected SMS. - :ivar status: The new lifecycle status. Known values are: "active" and "suspended". - :vartype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :ivar label: The replacement display label. Omit it to preserve the current value; use null to - clear it. - :vartype label: str - :ivar connection_name: The replacement Foundry connection name. This property is valid only for - a Teams Phone extensibility binding; a Twilio binding's connection is immutable. - :vartype connection_name: str - :ivar phone_number: The replacement Teams Phone extensibility display phone number. Omit it to - preserve the current value; use null to clear it. This property is valid only for a Teams Phone - extensibility binding. - :vartype phone_number: str + :ivar secret: Required; no default. True returns a private reference, false returns the value. + Privacy cannot be downgraded after collection starts. Required. + :vartype secret: bool + :ivar output_variable_name: Preferred bare name for the output variable, required for ``secret: + true`` and forbidden otherwise. + :vartype output_variable_name: str + :ivar timeout_seconds: Total deadline in seconds (1-300), including receiver setup. Overrides + the Agent timeout; if both are omitted, defaults to 60. Duplicate calls do not reset it. + :vartype timeout_seconds: int + :ivar from_phone_number: The expected SMS sender in canonical E.164 form, explicitly selected + at start without Caller ID fallback. This is routing, not authenticated identity. Required. + :vartype from_phone_number: str """ - status: Optional[Union[str, "_models.TelephonyBindingStatus"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The new lifecycle status. Known values are: \"active\" and \"suspended\".""" - label: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The replacement display label. Omit it to preserve the current value; use null to clear it.""" - connection_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The replacement Foundry connection name. This property is valid only for a Teams Phone - extensibility binding; a Twilio binding's connection is immutable.""" - phone_number: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The replacement Teams Phone extensibility display phone number. Omit it to preserve the current - value; use null to clear it. This property is valid only for a Teams Phone extensibility - binding.""" + secret: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required; no default. True returns a private reference, false returns the value. Privacy cannot + be downgraded after collection starts. Required.""" + output_variable_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Preferred bare name for the output variable, required for ``secret: true`` and forbidden + otherwise.""" + timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total deadline in seconds (1-300), including receiver setup. Overrides the Agent timeout; if + both are omitted, defaults to 60. Duplicate calls do not reset it.""" + from_phone_number: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The expected SMS sender in canonical E.164 form, explicitly selected at start without Caller ID + fallback. This is routing, not authenticated identity. Required.""" @overload def __init__( self, *, - status: Optional[Union[str, "_models.TelephonyBindingStatus"]] = None, - label: Optional[str] = None, - connection_name: Optional[str] = None, - phone_number: Optional[str] = None, + secret: bool, + from_phone_number: str, + output_variable_name: Optional[str] = None, + timeout_seconds: Optional[int] = None, ) -> None: ... @overload @@ -27271,23 +36940,35 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UpdateToolboxRequest(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """UpdateToolboxRequest. +class VoiceAgentCollectSmsSystemTool( + VoiceAgentSystemTool, discriminator="collect_sms" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Collects one complete SMS from an explicitly selected sender. - :ivar 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. - :vartype default_version: str + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``collect_sms``. Required. Collects one + complete SMS from an explicitly selected sender. + :vartype name: str or ~azure.ai.projects.models.COLLECT_SMS """ - default_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """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.""" + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.COLLECT_SMS] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``collect_sms``. Required. Collects one complete SMS + from an explicitly selected sender.""" @overload def __init__( self, *, - default_version: str, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -27299,34 +36980,210 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.name = VoiceAgentSystemToolName.COLLECT_SMS # type: ignore -class UserConversationSimulationAudioEffectsConfiguration( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Configures effects applied to simulated conversation audio. +class VoiceAgentDefinition( + VoiceAgentBaseDefinition, discriminator="realtime" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """The voice agent definition. Its configuration (model, instructions, audio, tools, and optional + avatar) drives a managed speech-to-speech experience. Establish realtime voice sessions through + ``GET /agents/{agent_name}/endpoint/protocols/voice``. Every create or update produces a new + immutable version. - :ivar effects: Effects to apply to simulated audio. - :vartype effects: list[str or ~azure.ai.projects.models.UserConversationSimulationAudioEffect] - :ivar volume_percentage: Volume of the configured audio effects, as a percentage from 1 through - 100. When omitted, the service defaults to 15. - :vartype volume_percentage: int + :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. + :vartype rai_config: ~azure.ai.projects.models.RaiConfig + :ivar kind: Always voice. Required. VOICE. + :vartype kind: str or ~azure.ai.projects.models.VOICE + :ivar instructions: Frontend instructions, templated with structured_inputs. Backend + instructions belong in delegation.responses. + :vartype instructions: str + :ivar structured_inputs: Template inputs for session instructions and supported greetings. + :vartype structured_inputs: dict[str, ~azure.ai.projects.models.StructuredInputDefinition] + :ivar store: Persists conversation content and audio in Foundry, not native Live recordings. + Defaults to false. + :vartype store: bool + :ivar sub_protocol: Selects the Realtime protocol. Required. REALTIME. + :vartype sub_protocol: str or ~azure.ai.projects.models.REALTIME + :ivar model_type: How the model backing this voice agent is served. Required with ``model`` for + a model-backed voice agent and omitted when ``conversation_engine`` is provided. This is + independent of the architecture (realtime or cascaded), which the service derives from the + selected model. Known values are: "managed" and "self_deployed". + :vartype model_type: str or ~azure.ai.projects.models.VoiceModelType + :ivar model: The model to use for this agent. Required with ``model_type`` for a model-backed + voice agent and omitted when ``conversation_engine`` is provided. The model must support + realtime or cascaded voice. + :vartype model: str + :ivar conversation_engine: The engine that owns conversation handling for this voice agent. + Exactly one of this property and the model-backed configuration (``model_type`` with ``model``) + must be provided. When this property is provided, ``model_type``, ``model``, ``instructions``, + ``tools``, and ``tool_choice`` must be omitted, and ``greeting.tool_choice`` cannot be + ``required``, because the engine owns the conversation logic. The initial implementation + supports a hosted-agent engine. + :vartype conversation_engine: ~azure.ai.projects.models.VoiceConversationEngine + :ivar greeting: Optional session-start greeting. Template mode speaks exact rendered text; + LLM-generated mode asks the session model to author the opening response and may use configured + tools. + :vartype greeting: ~azure.ai.projects.models.VoiceAgentGreetingConfig + :ivar audio: The audio configuration, including input and output formats, voice, turn + detection, noise reduction, and transcription. These values are session defaults; a client may + override supported fields when connecting. + :vartype audio: ~azure.ai.projects.models.VoiceAgentAudioConfig + :ivar soundscape: Optional background ambience and event cues, stored with the agent version + and separate from the audio configuration. Currently rendered only for telephony calls, not + browser WebRTC or direct voice WebSocket sessions. Omit this property to disable all auxiliary + audio. Persisted conversation recordings do not include the soundscape mix. + :vartype soundscape: ~azure.ai.projects.models.VoiceAgentSoundscapeConfig + :ivar output_modalities: The output modalities the agent produces. Defaults to ``["audio"]``. + ``animation`` and ``avatar`` are available when an avatar is configured. + :vartype output_modalities: list[str or ~azure.ai.projects.models.VoiceOutputModality] + :ivar max_output_tokens: The maximum output-token count for one response. Is either a int type + or a Literal["inf"] type. + :vartype max_output_tokens: int or str + :ivar include: Additional fields to include in service outputs. + :vartype include: list[str or ~azure.ai.projects.models.VoiceAgentSessionIncludeOption] + :ivar interim_response: Interim-response settings for latency and tool execution. + :vartype interim_response: ~azure.ai.projects.models.VoiceAgentInterimResponseConfig + :ivar avatar: Optional avatar configuration. These values are session defaults and may be + overridden when connecting. + :vartype avatar: ~azure.ai.projects.models.VoiceAgentAvatarConfig + :ivar tools: The tools the voice agent may use. Supported tool kinds are ``function`` (executed + by the client), ``mcp``, ``system`` (service-managed session controls), and ``toolbox``. + Server-side tools such as ``web_search``, ``azure_ai_search``, and ``openapi`` are provided + through a toolbox rather than declared directly. + :vartype tools: list[~azure.ai.projects.models.VoiceAgentTool] + :ivar tool_choice: How the model chooses tools for generated responses. ``none`` prevents tool + calls, ``auto`` lets the model decide, ``required`` requires at least one tool call, and a + specific function or MCP tool can be selected with an object. Defaults to ``auto``. Is one of + the following types: Literal["none"], Literal["auto"], Literal["required"], ToolChoiceFunction, + ToolChoiceMCP + :vartype tool_choice: str or str or str or ~azure.ai.projects.models.ToolChoiceFunction or + ~azure.ai.projects.models.ToolChoiceMCP + :ivar parallel_tool_calls: Whether the model may call multiple tools in parallel. + :vartype parallel_tool_calls: bool + :ivar subagent_config: Optional subagent configuration. Set ``subagent_type`` to ``delegate`` + for delegated background specialists or ``inline`` for inline voice subagents. + :vartype subagent_config: ~azure.ai.projects.models.VoiceAgentSubagentConfig + :ivar post_call: Optional post-call delivery configuration. After each session ends, the + service notifies the configured destinations. + :vartype post_call: ~azure.ai.projects.models.VoiceAgentPostCallConfig """ - effects: Optional[list[Union[str, "_models.UserConversationSimulationAudioEffect"]]] = rest_field( + __mapping__: dict[str, _Model] = {} + sub_protocol: Literal[VoiceAgentSubProtocol.REALTIME] = rest_discriminator(name="sub_protocol", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Selects the Realtime protocol. Required. REALTIME.""" + model_type: Optional[Union[str, "_models.VoiceModelType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """How the model backing this voice agent is served. Required with ``model`` for a model-backed + voice agent and omitted when ``conversation_engine`` is provided. This is independent of the + architecture (realtime or cascaded), which the service derives from the selected model. Known + values are: \"managed\" and \"self_deployed\".""" + model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model to use for this agent. Required with ``model_type`` for a model-backed voice agent + and omitted when ``conversation_engine`` is provided. The model must support realtime or + cascaded voice.""" + conversation_engine: Optional["_models.VoiceConversationEngine"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The engine that owns conversation handling for this voice agent. Exactly one of this property + and the model-backed configuration (``model_type`` with ``model``) must be provided. When this + property is provided, ``model_type``, ``model``, ``instructions``, ``tools``, and + ``tool_choice`` must be omitted, and ``greeting.tool_choice`` cannot be ``required``, because + the engine owns the conversation logic. The initial implementation supports a hosted-agent + engine.""" + greeting: Optional["_models.VoiceAgentGreetingConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional session-start greeting. Template mode speaks exact rendered text; LLM-generated mode + asks the session model to author the opening response and may use configured tools.""" + audio: Optional["_models.VoiceAgentAudioConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The audio configuration, including input and output formats, voice, turn detection, noise + reduction, and transcription. These values are session defaults; a client may override + supported fields when connecting.""" + soundscape: Optional["_models.VoiceAgentSoundscapeConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional background ambience and event cues, stored with the agent version and separate from + the audio configuration. Currently rendered only for telephony calls, not browser WebRTC or + direct voice WebSocket sessions. Omit this property to disable all auxiliary audio. Persisted + conversation recordings do not include the soundscape mix.""" + output_modalities: Optional[list[Union[str, "_models.VoiceOutputModality"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The output modalities the agent produces. Defaults to ``[\"audio\"]``. ``animation`` and + ``avatar`` are available when an avatar is configured.""" + max_output_tokens: Optional["_unions.VoiceAgentMaxOutputTokens"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The maximum output-token count for one response. Is either a int type or a Literal[\"inf\"] + type.""" + include: Optional[list[Union[str, "_models.VoiceAgentSessionIncludeOption"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Additional fields to include in service outputs.""" + interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Interim-response settings for latency and tool execution.""" + avatar: Optional["_models.VoiceAgentAvatarConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional avatar configuration. These values are session defaults and may be overridden when + connecting.""" + tools: Optional[list["_models.VoiceAgentTool"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The tools the voice agent may use. Supported tool kinds are ``function`` (executed by the + client), ``mcp``, ``system`` (service-managed session controls), and ``toolbox``. Server-side + tools such as ``web_search``, ``azure_ai_search``, and ``openapi`` are provided through a + toolbox rather than declared directly.""" + tool_choice: Optional["_unions.VoiceAgentToolChoice"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Effects to apply to simulated audio.""" - volume_percentage: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Volume of the configured audio effects, as a percentage from 1 through 100. When omitted, the - service defaults to 15.""" + """How the model chooses tools for generated responses. ``none`` prevents tool calls, ``auto`` + lets the model decide, ``required`` requires at least one tool call, and a specific function or + MCP tool can be selected with an object. Defaults to ``auto``. Is one of the following types: + Literal[\"none\"], Literal[\"auto\"], Literal[\"required\"], ToolChoiceFunction, ToolChoiceMCP""" + parallel_tool_calls: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the model may call multiple tools in parallel.""" + subagent_config: Optional["_models.VoiceAgentSubagentConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional subagent configuration. Set ``subagent_type`` to ``delegate`` for delegated background + specialists or ``inline`` for inline voice subagents.""" + post_call: Optional["_models.VoiceAgentPostCallConfig"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional post-call delivery configuration. After each session ends, the service notifies the + configured destinations.""" @overload def __init__( self, *, - effects: Optional[list[Union[str, "_models.UserConversationSimulationAudioEffect"]]] = None, - volume_percentage: Optional[int] = None, + rai_config: Optional["_models.RaiConfig"] = None, + instructions: Optional[str] = None, + structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = None, + store: Optional[bool] = None, + model_type: Optional[Union[str, "_models.VoiceModelType"]] = None, + model: Optional[str] = None, + conversation_engine: Optional["_models.VoiceConversationEngine"] = None, + greeting: Optional["_models.VoiceAgentGreetingConfig"] = None, + audio: Optional["_models.VoiceAgentAudioConfig"] = None, + soundscape: Optional["_models.VoiceAgentSoundscapeConfig"] = None, + output_modalities: Optional[list[Union[str, "_models.VoiceOutputModality"]]] = None, + max_output_tokens: Optional["_unions.VoiceAgentMaxOutputTokens"] = None, + include: Optional[list[Union[str, "_models.VoiceAgentSessionIncludeOption"]]] = None, + interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = None, + avatar: Optional["_models.VoiceAgentAvatarConfig"] = None, + tools: Optional[list["_models.VoiceAgentTool"]] = None, + tool_choice: Optional["_unions.VoiceAgentToolChoice"] = None, + parallel_tool_calls: Optional[bool] = None, + subagent_config: Optional["_models.VoiceAgentSubagentConfig"] = None, + post_call: Optional["_models.VoiceAgentPostCallConfig"] = None, ) -> None: ... @overload @@ -27338,58 +37195,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.sub_protocol = VoiceAgentSubProtocol.REALTIME # type: ignore -class UserConversationSimulationConfiguration(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Configures the number, length, audio effects, and simulated user behavior of conversations. +class VoiceAgentSubagentConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration for delegated background specialists or inline voice subagents. For compatibility + with existing delegate configurations, the service treats an omitted ``subagent_type`` as + ``delegate``. - :ivar max_num_turns: Hard limit on turns in each conversation. When omitted, the service - defaults to 20. - :vartype max_num_turns: int - :ivar conversation_repetitions: Number of independent conversation repetitions for each test - case. Defaults to 1 when not specified at either the data-source or test-case level. - :vartype conversation_repetitions: int - :ivar desired_num_turns: Target number of turns in each conversation. The effective value - cannot exceed the effective ``max_num_turns``. When omitted, no target is set and the - simulation model determines the conversation length dynamically from the scenario. - :vartype desired_num_turns: int - :ivar audio_effects: Audio effects applied to voice conversation simulations. This property is - ignored for text-only simulations. - :vartype audio_effects: - ~azure.ai.projects.models.UserConversationSimulationAudioEffectsConfiguration - :ivar user_behavior: Conversation behavior of the simulated user. - :vartype user_behavior: - ~azure.ai.projects.models.UserConversationSimulationUserBehaviorConfiguration + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentDelegateSubagentConfig, VoiceAgentInlineSubagentConfig + + :ivar subagent_type: The subagent mode. Required. Known values are: "delegate" and "inline". + :vartype subagent_type: str or ~azure.ai.projects.models.VoiceAgentSubagentType """ - max_num_turns: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Hard limit on turns in each conversation. When omitted, the service defaults to 20.""" - conversation_repetitions: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of independent conversation repetitions for each test case. Defaults to 1 when not - specified at either the data-source or test-case level.""" - desired_num_turns: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Target number of turns in each conversation. The effective value cannot exceed the effective - ``max_num_turns``. When omitted, no target is set and the simulation model determines the - conversation length dynamically from the scenario.""" - audio_effects: Optional["_models.UserConversationSimulationAudioEffectsConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Audio effects applied to voice conversation simulations. This property is ignored for text-only - simulations.""" - user_behavior: Optional["_models.UserConversationSimulationUserBehaviorConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + __mapping__: dict[str, _Model] = {} + subagent_type: str = rest_discriminator( + name="subagent_type", visibility=["read", "create", "update", "delete", "query"] ) - """Conversation behavior of the simulated user.""" + """The subagent mode. Required. Known values are: \"delegate\" and \"inline\".""" @overload def __init__( self, *, - max_num_turns: Optional[int] = None, - conversation_repetitions: Optional[int] = None, - desired_num_turns: Optional[int] = None, - audio_effects: Optional["_models.UserConversationSimulationAudioEffectsConfiguration"] = None, - user_behavior: Optional["_models.UserConversationSimulationUserBehaviorConfiguration"] = None, + subagent_type: str, ) -> None: ... @overload @@ -27403,27 +37234,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserConversationSimulationInterruptionConfiguration( - _Model -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Configuration for simulated user interruption behavior. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - UserConversationSimulationDefaultInterruptionConfiguration +class VoiceAgentDelegateSubagentConfig( + VoiceAgentSubagentConfig, discriminator="delegate" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration for referenced Foundry agents invoked as delegated background specialists. - :ivar type: The interruption type. Required. Default value is None. - :vartype type: str + :ivar subagent_type: The subagent mode for delegated background specialists. Required. + Referenced Foundry agents invoked as delegated background specialists. + :vartype subagent_type: str or ~azure.ai.projects.models.DELEGATE + :ivar subagents: The sibling Foundry text agents, in the same project, that this Voice Agent + may consult. Required. + :vartype subagents: list[~azure.ai.projects.models.VoiceAgentSubagent] """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The interruption type. Required. Default value is None.""" + subagent_type: Literal[VoiceAgentSubagentType.DELEGATE] = rest_discriminator(name="subagent_type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The subagent mode for delegated background specialists. Required. Referenced Foundry agents + invoked as delegated background specialists.""" + subagents: list["_models.VoiceAgentSubagent"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The sibling Foundry text agents, in the same project, that this Voice Agent may consult. + Required.""" @overload def __init__( self, *, - type: str, + subagents: list["_models.VoiceAgentSubagent"], ) -> None: ... @overload @@ -27435,23 +37272,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.subagent_type = VoiceAgentSubagentType.DELEGATE # type: ignore -class UserConversationSimulationDefaultInterruptionConfiguration( - UserConversationSimulationInterruptionConfiguration, discriminator="default" -): # pylint: disable=name-too-long - """Configures the default interruption behavior for the simulated user. +class VoiceAgentDigitRecognitionSystemTool( + VoiceAgentSystemTool, discriminator="digit_recognition" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Retrieves the unchanged transcript of the last user audio turn. - :ivar type: The interruption type, always ``default``. Required. Default value is "default". - :vartype type: str + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``digit_recognition``. Required. + Retrieves the unchanged transcript of the last user audio turn. + :vartype name: str or ~azure.ai.projects.models.DIGIT_RECOGNITION """ - type: Literal["default"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The interruption type, always ``default``. Required. Default value is \"default\".""" + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.DIGIT_RECOGNITION] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``digit_recognition``. Required. Retrieves the + unchanged transcript of the last user audio turn.""" @overload def __init__( self, + *, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -27463,50 +37315,36 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "default" # type: ignore + self.name = VoiceAgentSystemToolName.DIGIT_RECOGNITION # type: ignore -class UserConversationSimulationTestCase(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Defines one test scenario. Simulation configuration properties specified here override the - corresponding data-source defaults. +class VoiceAgentDtmfFixedLengthCompletionMode(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Complete immediately after exactly length digits. Other modes' fields are not accepted. - :ivar test_case_id: Identifier for the test case. When omitted, the service generates a random - identifier. - :vartype test_case_id: str - :ivar test_case_category: Category used to group related test cases. When omitted, the service - leaves the category null. - :vartype test_case_category: str - :ivar test_case_description: Scenario, simulated user goal, and behavioral constraints that - guide the conversation. The length must be from 1 through 2,500 characters. - :vartype test_case_description: str - :ivar simulation_configuration: Configuration for conversations generated from this test case. - Each specified property overrides the corresponding property in - ``default_simulation_configuration``. - :vartype simulation_configuration: - ~azure.ai.projects.models.UserConversationSimulationConfiguration + :ivar inter_digit_timeout_seconds: Seconds between digits, reset after each digit; defaults to + 5. + :vartype inter_digit_timeout_seconds: int + :ivar type: Select fixed-length completion. Required. Default value is "fixed_length". + :vartype type: str + :ivar length: The number of digits to collect; defaults to six. There is no terminator or + separate minimum/maximum pair. + :vartype length: int """ - test_case_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Identifier for the test case. When omitted, the service generates a random identifier.""" - test_case_category: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Category used to group related test cases. When omitted, the service leaves the category null.""" - test_case_description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Scenario, simulated user goal, and behavioral constraints that guide the conversation. The - length must be from 1 through 2,500 characters.""" - simulation_configuration: Optional["_models.UserConversationSimulationConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configuration for conversations generated from this test case. Each specified property - overrides the corresponding property in ``default_simulation_configuration``.""" + inter_digit_timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Seconds between digits, reset after each digit; defaults to 5.""" + type: Literal["fixed_length"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Select fixed-length completion. Required. Default value is \"fixed_length\".""" + length: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of digits to collect; defaults to six. There is no terminator or separate + minimum/maximum pair.""" @overload def __init__( self, *, - test_case_id: Optional[str] = None, - test_case_category: Optional[str] = None, - test_case_description: Optional[str] = None, - simulation_configuration: Optional["_models.UserConversationSimulationConfiguration"] = None, + inter_digit_timeout_seconds: Optional[int] = None, + length: Optional[int] = None, ) -> None: ... @overload @@ -27518,30 +37356,32 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["fixed_length"] = "fixed_length" -class UserConversationSimulationUserBehaviorConfiguration( +class VoiceAgentDtmfInterDigitSilenceCompletionMode( _Model ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Configures conversation behavior for the simulated user. + """Completes after nonempty input and an inter-digit pause, within service limits. No key or count + is configured; total deadline expiry takes precedence. - :ivar interruption: Configures how the simulated user interrupts the target while it is - speaking. Omit to disable interruption. - :vartype interruption: - ~azure.ai.projects.models.UserConversationSimulationInterruptionConfiguration + :ivar inter_digit_timeout_seconds: Seconds between digits, reset after each digit; defaults to + 5. + :vartype inter_digit_timeout_seconds: int + :ivar type: Select silence completion. Required. Default value is "inter_digit_silence". + :vartype type: str """ - interruption: Optional["_models.UserConversationSimulationInterruptionConfiguration"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Configures how the simulated user interrupts the target while it is speaking. Omit to disable - interruption.""" + inter_digit_timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Seconds between digits, reset after each digit; defaults to 5.""" + type: Literal["inter_digit_silence"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Select silence completion. Required. Default value is \"inter_digit_silence\".""" @overload def __init__( self, *, - interruption: Optional["_models.UserConversationSimulationInterruptionConfiguration"] = None, + inter_digit_timeout_seconds: Optional[int] = None, ) -> None: ... @overload @@ -27553,39 +37393,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["inter_digit_silence"] = "inter_digit_silence" -class UserProfileMemoryItem( - MemoryItem, discriminator="user_profile" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A memory item specifically containing user profile information extracted from conversations, - such as preferences, interests, and personal details. +class VoiceAgentDtmfTerminatorCompletionMode(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Completes when the configured end key follows nonempty digits within service limits. No digit + count or length bounds are configured. - :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. User profile information extracted from - conversations. - :vartype kind: str or ~azure.ai.projects.models.USER_PROFILE + :ivar inter_digit_timeout_seconds: Seconds between digits, reset after each digit; defaults to + 5. + :vartype inter_digit_timeout_seconds: int + :ivar type: Select confirmation-key completion. Required. Default value is "terminator". + :vartype type: str + :ivar terminator: Required confirmation key; excluded from the collected value. Required. Known + values are: "#" and "*". + :vartype terminator: str or ~azure.ai.projects.models.VoiceAgentDtmfTerminator """ - kind: Literal[MemoryItemKind.USER_PROFILE] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The kind of the memory item. Required. User profile information extracted from conversations.""" + inter_digit_timeout_seconds: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Seconds between digits, reset after each digit; defaults to 5.""" + type: Literal["terminator"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Select confirmation-key completion. Required. Default value is \"terminator\".""" + terminator: Union[str, "_models.VoiceAgentDtmfTerminator"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required confirmation key; excluded from the collected value. Required. Known values are: \"#\" + and \"*\".""" @overload def __init__( self, *, - memory_id: str, - updated_at: datetime.datetime, - scope: str, - content: str, + terminator: Union[str, "_models.VoiceAgentDtmfTerminator"], + inter_digit_timeout_seconds: Optional[int] = None, ) -> None: ... @overload @@ -27597,28 +37437,42 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = MemoryItemKind.USER_PROFILE # type: ignore + self.type: Literal["terminator"] = "terminator" -class VersionIndicator(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Version indicator determining which agent version backs the session. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - VersionRefIndicator +class VoiceAgentEchoCancellation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Server-side echo cancellation settings for input audio. - :ivar type: The type of version indicator. Required. "version_ref" - :vartype type: str or ~azure.ai.projects.models.VersionIndicatorType + :ivar type: The echo cancellation implementation. Always ``server_echo_cancellation``. + Required. Default value is "server_echo_cancellation". + :vartype type: str + :ivar reference_source: Whether reference audio comes from server playback or a client-provided + channel. Known values are: "server" and "client". + :vartype reference_source: str or + ~azure.ai.projects.models.VoiceAgentEchoCancellationReferenceSource + :ivar channels: The number of input channels. Use two interleaved channels when + ``reference_source`` is ``client``. + :vartype channels: int """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of version indicator. Required. \"version_ref\"""" + type: Literal["server_echo_cancellation"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The echo cancellation implementation. Always ``server_echo_cancellation``. Required. Default + value is \"server_echo_cancellation\".""" + reference_source: Optional[Union[str, "_models.VoiceAgentEchoCancellationReferenceSource"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Whether reference audio comes from server playback or a client-provided channel. Known values + are: \"server\" and \"client\".""" + channels: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of input channels. Use two interleaved channels when ``reference_source`` is + ``client``.""" @overload def __init__( self, *, - type: str, + reference_source: Optional[Union[str, "_models.VoiceAgentEchoCancellationReferenceSource"]] = None, + channels: Optional[int] = None, ) -> None: ... @overload @@ -27630,30 +37484,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["server_echo_cancellation"] = "server_echo_cancellation" -class VersionRefIndicator( - VersionIndicator, discriminator="version_ref" +class VoiceAgentEndConversationSystemTool( + VoiceAgentSystemTool, discriminator="end_conversation" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """Version indicator that references a specific agent version by name. + """A service-managed control that ends the active conversation. - :ivar type: Discriminator value for version_ref. Required. Direct reference to a specific agent - version. - :vartype type: str or ~azure.ai.projects.models.VERSION_REF - :ivar agent_version: The agent version identifier returned by the agent version APIs. Required. - :vartype agent_version: str + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``end_conversation``. Required. Ends the + active conversation. + :vartype name: str or ~azure.ai.projects.models.END_CONVERSATION """ - type: Literal[VersionIndicatorType.VERSION_REF] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Discriminator value for version_ref. Required. Direct reference to a specific agent version.""" - agent_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent version identifier returned by the agent version APIs. Required.""" + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.END_CONVERSATION] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``end_conversation``. Required. Ends the active + conversation.""" @overload def __init__( self, *, - agent_version: str, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -27665,26 +37527,46 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = VersionIndicatorType.VERSION_REF # type: ignore + self.name = VoiceAgentSystemToolName.END_CONVERSATION # type: ignore -class VersionSelector(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """VersionSelector. +class VoiceAgentEndOfUtteranceDetection(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Semantic end-of-utterance detection configuration. - :ivar version_selection_rules: Required. - :vartype version_selection_rules: list[~azure.ai.projects.models.VersionSelectionRule] + :ivar model: The semantic detection model. Required. Known values are: "semantic_detection_v1", + "semantic_detection_v1_en", "semantic_detection_v1_multilingual", and + "smart_end_of_turn_detection". + :vartype model: str or ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetectionModel + :ivar threshold_level: The sensitivity threshold. Known values are: "low", "medium", "high", + and "default". + :vartype threshold_level: str or + ~azure.ai.projects.models.VoiceAgentEndOfUtteranceThresholdLevel + :ivar timeout_ms: The detection timeout in milliseconds. + :vartype timeout_ms: ~datetime.timedelta """ - version_selection_rules: list["_models.VersionSelectionRule"] = rest_field( + model: Union[str, "_models.VoiceAgentEndOfUtteranceDetectionModel"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Required.""" + """The semantic detection model. Required. Known values are: \"semantic_detection_v1\", + \"semantic_detection_v1_en\", \"semantic_detection_v1_multilingual\", and + \"smart_end_of_turn_detection\".""" + threshold_level: Optional[Union[str, "_models.VoiceAgentEndOfUtteranceThresholdLevel"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The sensitivity threshold. Known values are: \"low\", \"medium\", \"high\", and \"default\".""" + timeout_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """The detection timeout in milliseconds.""" @overload def __init__( self, *, - version_selection_rules: list["_models.VersionSelectionRule"], + model: Union[str, "_models.VoiceAgentEndOfUtteranceDetectionModel"], + threshold_level: Optional[Union[str, "_models.VoiceAgentEndOfUtteranceThresholdLevel"]] = None, + timeout_ms: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -27698,28 +37580,25 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAnimationConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Animation settings for a voice-agent session. +class VoiceAgentPostCallDestination(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A post-call destination. - :ivar model_name: The animation model name. - :vartype model_name: str - :ivar outputs: The requested animation output kinds. - :vartype outputs: list[str or ~azure.ai.projects.models.VoiceAgentAnimationOutputType] + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentEventGridPostCallDestination, VoiceAgentRoutinePostCallDestination + + :ivar type: The destination type. Required. Known values are: "event_grid" and "routine". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentPostCallDestinationType """ - model_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The animation model name.""" - outputs: Optional[list[Union[str, "_models.VoiceAgentAnimationOutputType"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The requested animation output kinds.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The destination type. Required. Known values are: \"event_grid\" and \"routine\".""" @overload def __init__( self, *, - model_name: Optional[str] = None, - outputs: Optional[list[Union[str, "_models.VoiceAgentAnimationOutputType"]]] = None, + type: str, ) -> None: ... @overload @@ -27733,31 +37612,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAudioConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The audio configuration for a voice agent. These values are session defaults and may be - overridden when connecting. +class VoiceAgentEventGridPostCallDestination( + VoiceAgentPostCallDestination, discriminator="event_grid" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """An Event Grid connection that receives post-call events. - :ivar input: Input (microphone) audio configuration. - :vartype input: ~azure.ai.projects.models.VoiceAgentAudioInputConfig - :ivar output: Output (agent speech) audio configuration. - :vartype output: ~azure.ai.projects.models.VoiceAgentAudioOutputConfig + :ivar type: The destination type. Always ``event_grid``. Required. An Event Grid connection. + :vartype type: str or ~azure.ai.projects.models.EVENT_GRID + :ivar connection_name: The name of the Event Grid connection. Required. + :vartype connection_name: str """ - input: Optional["_models.VoiceAgentAudioInputConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Input (microphone) audio configuration.""" - output: Optional["_models.VoiceAgentAudioOutputConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Output (agent speech) audio configuration.""" + type: Literal[VoiceAgentPostCallDestinationType.EVENT_GRID] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The destination type. Always ``event_grid``. Required. An Event Grid connection.""" + connection_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the Event Grid connection. Required.""" @overload def __init__( self, *, - input: Optional["_models.VoiceAgentAudioInputConfig"] = None, - output: Optional["_models.VoiceAgentAudioOutputConfig"] = None, + connection_name: str, ) -> None: ... @overload @@ -27769,202 +37644,77 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = VoiceAgentPostCallDestinationType.EVENT_GRID # type: ignore -class VoiceAgentAudioInputConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Input audio configuration for a voice agent. +class VoiceAgentFunctionTool( + VoiceAgentTool, discriminator="function" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A native function tool executed by the client. - :ivar format: The input audio format. - :vartype format: ~azure.ai.projects.models.RealtimeAudioFormats - :ivar noise_reduction: Input noise reduction. Set to null to disable. - :vartype noise_reduction: ~azure.ai.projects.models.VoiceAgentNoiseReduction - :ivar turn_detection: Turn (end-of-speech) detection. Server-side turn detection is enabled by - default; set to null to disable it, in which case the client must trigger responses manually. - :vartype turn_detection: ~azure.ai.projects.models.VoiceAgentTurnDetectionConfig - :ivar echo_cancellation: Optional server-side echo cancellation settings. - :vartype echo_cancellation: ~azure.ai.projects.models.VoiceAgentEchoCancellation - :ivar transcription: Asynchronous input-audio transcription. Set to null to disable - transcription. - :vartype transcription: ~azure.ai.projects.models.VoiceAgentInputTranscription + :ivar description: The description of the function, including guidance on when and how to call + it, and guidance about what to tell the user when calling (if anything). + :vartype description: str + :ivar parameters: Parameters of the function in JSON Schema. + :vartype parameters: ~azure.ai.projects.models.RealtimeFunctionToolParameters + :ivar type: Required. A native function tool executed by the client. + :vartype type: str or ~azure.ai.projects.models.FUNCTION + :ivar name: The function name. Required. + :vartype name: str """ - format: Optional["_models.RealtimeAudioFormats"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The input audio format.""" - noise_reduction: Optional["_models.VoiceAgentNoiseReduction"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Input noise reduction. Set to null to disable.""" - turn_detection: Optional["_models.VoiceAgentTurnDetectionConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Turn (end-of-speech) detection. Server-side turn detection is enabled by default; set to null - to disable it, in which case the client must trigger responses manually.""" - echo_cancellation: Optional["_models.VoiceAgentEchoCancellation"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional server-side echo cancellation settings.""" - transcription: Optional["_models.VoiceAgentInputTranscription"] = rest_field( + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The description of the function, including guidance on when and how to call it, and guidance + about what to tell the user when calling (if anything).""" + parameters: Optional["_models.RealtimeFunctionToolParameters"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Asynchronous input-audio transcription. Set to null to disable transcription.""" + """Parameters of the function in JSON Schema.""" + type: Literal[VoiceAgentToolType.FUNCTION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. A native function tool executed by the client.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The function name. Required.""" @overload def __init__( self, *, - format: Optional["_models.RealtimeAudioFormats"] = None, - noise_reduction: Optional["_models.VoiceAgentNoiseReduction"] = None, - turn_detection: Optional["_models.VoiceAgentTurnDetectionConfig"] = None, - echo_cancellation: Optional["_models.VoiceAgentEchoCancellation"] = None, - transcription: Optional["_models.VoiceAgentInputTranscription"] = None, + name: str, + description: Optional[str] = None, + parameters: Optional["_models.RealtimeFunctionToolParameters"] = 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 VoiceAgentAudioOutputConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Output audio configuration for a voice agent. - Provider-specific fields are selected by ``voice_type``: - - * `openai`: `voice` and `speed`. - * `azure-standard`: `voice`, `voice_locale`, `speed`, `voice_temperature`, `custom_lexicon_url`, - `custom_text_normalization_url`, `prefer_locales`, `style`, `pitch`, and `volume`. - * `azure-custom`: all `azure-standard` fields except `style`, plus `custom_voice_endpoint_id`. - * `azure-personal`: all `azure-standard` fields except `style`, plus `personal_voice_model`. - * `avatar-voice-sync`: all `azure-standard` fields except `voice` and `style`, plus `personal_voice_model`; the - voice name is derived from the avatar. - * `azure-realtime-native`: `voice` and `speed`. `format` and `output_audio_timestamp_types` apply to every voice - type. - - :ivar format: The output audio format. Applies to every ``voice_type`` and defaults to 24 kHz - PCM. - :vartype format: ~azure.ai.projects.models.RealtimeAudioFormats - :ivar voice: The voice name or identifier. Applies to ``openai``, ``azure-standard``, - ``azure-custom``, ``azure-personal``, and ``azure-realtime-native``. It does not apply to - ``avatar-voice-sync``, which derives the voice name from the avatar. - :vartype voice: str - :ivar voice_type: The voice implementation. Known values are: "openai", "azure-standard", - "azure-custom", "azure-personal", "avatar-voice-sync", and "azure-realtime-native". - :vartype voice_type: str or ~azure.ai.projects.models.VoiceType - :ivar voice_locale: The enforced BCP-47 output locale. Applies to ``azure-standard``, - ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. - :vartype voice_locale: str - :ivar speed: The numeric output speed multiplier. Applies to all known ``voice_type`` values - and defaults to 1. - :vartype speed: float - :ivar voice_temperature: The voice variation temperature. Applies to ``azure-standard``, - ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. - :vartype voice_temperature: float - :ivar custom_lexicon_url: The URL of a custom pronunciation lexicon. Applies to - ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. - :vartype custom_lexicon_url: str - :ivar custom_text_normalization_url: The URL of a custom text-normalization configuration. - Applies to ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. - :vartype custom_text_normalization_url: str - :ivar prefer_locales: Preferred BCP-47 locales for multilingual synthesis. Applies to - ``azure-standard``, ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``. - :vartype prefer_locales: list[str] - :ivar style: The voice speaking style. Applies only when ``voice_type`` is ``azure-standard``. - :vartype style: str - :ivar pitch: The voice pitch adjustment. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``. - :vartype pitch: str - :ivar volume: The voice volume adjustment. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``. - :vartype volume: str - :ivar custom_voice_endpoint_id: The Azure custom-voice deployment endpoint identifier. Applies - only when ``voice_type`` is ``azure-custom``. - :vartype custom_voice_endpoint_id: str - :ivar personal_voice_model: The Azure personal or avatar voice model. Applies only when - ``voice_type`` is ``azure-personal`` or ``avatar-voice-sync``. - :vartype personal_voice_model: str - :ivar output_audio_timestamp_types: Timestamp kinds to include with output audio. Applies to - every ``voice_type``. - :vartype output_audio_timestamp_types: list[str or - ~azure.ai.projects.models.VoiceAgentAudioTimestampType] - """ - - format: Optional["_models.RealtimeAudioFormats"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The output audio format. Applies to every ``voice_type`` and defaults to 24 kHz PCM.""" - voice: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice name or identifier. Applies to ``openai``, ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``azure-realtime-native``. It does not apply to ``avatar-voice-sync``, - which derives the voice name from the avatar.""" - voice_type: Optional[Union[str, "_models.VoiceType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The voice implementation. Known values are: \"openai\", \"azure-standard\", \"azure-custom\", - \"azure-personal\", \"avatar-voice-sync\", and \"azure-realtime-native\".""" - voice_locale: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The enforced BCP-47 output locale. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``.""" - speed: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The numeric output speed multiplier. Applies to all known ``voice_type`` values and defaults to - 1.""" - voice_temperature: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice variation temperature. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``.""" - custom_lexicon_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The URL of a custom pronunciation lexicon. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``.""" - custom_text_normalization_url: Optional[str] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The URL of a custom text-normalization configuration. Applies to ``azure-standard``, - ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``.""" - prefer_locales: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Preferred BCP-47 locales for multilingual synthesis. Applies to ``azure-standard``, - ``azure-custom``, ``azure-personal``, and ``avatar-voice-sync``.""" - style: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice speaking style. Applies only when ``voice_type`` is ``azure-standard``.""" - pitch: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice pitch adjustment. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``.""" - volume: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice volume adjustment. Applies to ``azure-standard``, ``azure-custom``, - ``azure-personal``, and ``avatar-voice-sync``.""" - custom_voice_endpoint_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Azure custom-voice deployment endpoint identifier. Applies only when ``voice_type`` is - ``azure-custom``.""" - personal_voice_model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The Azure personal or avatar voice model. Applies only when ``voice_type`` is - ``azure-personal`` or ``avatar-voice-sync``.""" - output_audio_timestamp_types: Optional[list[Union[str, "_models.VoiceAgentAudioTimestampType"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Timestamp kinds to include with output audio. Applies to every ``voice_type``.""" + :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 = VoiceAgentToolType.FUNCTION # type: ignore + + +class VoiceAgentGreetingConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Session-start greeting configuration for a voice agent. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentLlmGeneratedGreetingConfig, VoiceAgentTemplateGreetingConfig + + :ivar type: The greeting mode. Required. Known values are: "template" and "llm_generated". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentGreetingMode + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The greeting mode. Required. Known values are: \"template\" and \"llm_generated\".""" @overload def __init__( self, *, - format: Optional["_models.RealtimeAudioFormats"] = None, - voice: Optional[str] = None, - voice_type: Optional[Union[str, "_models.VoiceType"]] = None, - voice_locale: Optional[str] = None, - speed: Optional[float] = None, - voice_temperature: Optional[float] = None, - custom_lexicon_url: Optional[str] = None, - custom_text_normalization_url: Optional[str] = None, - prefer_locales: Optional[list[str]] = None, - style: Optional[str] = None, - pitch: Optional[str] = None, - volume: Optional[str] = None, - custom_voice_endpoint_id: Optional[str] = None, - personal_voice_model: Optional[str] = None, - output_audio_timestamp_types: Optional[list[Union[str, "_models.VoiceAgentAudioTimestampType"]]] = None, + type: str, ) -> None: ... @overload @@ -27978,72 +37728,138 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAvatarConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Avatar configuration for a voice agent. These values are session defaults and may be overridden - when connecting. +class VoiceAgentHandoffCondition(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """One allowed outgoing handoff from an inline voice subagent. - :ivar type: The avatar type. Required. Known values are: "video_avatar" and "photo_avatar". - :vartype type: str or ~azure.ai.projects.models.VoiceAgentAvatarType - :ivar character: The avatar character identifier, e.g. 'lisa'. Required. - :vartype character: str - :ivar style: The avatar style, e.g. 'casual-sitting'. - :vartype style: str - :ivar customized: Whether the avatar is a customer-customized avatar. Defaults to false. - :vartype customized: bool - :ivar output_protocol: The transport used to deliver the avatar video stream. Known values are: - "webrtc" and "websocket". - :vartype output_protocol: str or ~azure.ai.projects.models.VoiceAgentAvatarOutputProtocol - :ivar model: The avatar model identifier. - :vartype model: str - :ivar video: Avatar video encoder and presentation settings. - :vartype video: ~azure.ai.projects.models.VoiceAgentAvatarVideoParams - :ivar scene: Avatar placement and motion settings. - :vartype scene: ~azure.ai.projects.models.VoiceAgentAvatarScene - :ivar output_audit_audio: Whether audit audio is emitted with avatar output. Defaults to false. - :vartype output_audit_audio: bool + :ivar id: The handoff condition identifier. Required. + :vartype id: str + :ivar target: The target subagent identifier or ``$entrypoint``. The containing subagent + supplies the source. Required. + :vartype target: str + :ivar condition: Natural-language routing guidance supplied alongside the active subagent + instructions, from 1 through 500 characters. This is not an executable Boolean predicate. + Required. + :vartype condition: str + :ivar cancel_on_interruption: Whether user interruption before commit cancels the pending + handoff. If omitted, the service defaults to false. + :vartype cancel_on_interruption: bool + :ivar delay_ms: The minimum delay before target activation, in milliseconds, from 0 through + 10000. If omitted, the service defaults to 0. + :vartype delay_ms: ~datetime.timedelta + :ivar transfer_message: Optional deterministic source-voice announcement played before target + activation. Supported by cascaded pipelines and realtime pipelines using local Azure TTS; + model-native realtime voice requires omission or null. At most 500 characters. If omitted or + null, no announcement is played. + :vartype transfer_message: str + :ivar target_response: Whether Voice Live automatically starts a response after target + activation. If omitted, the service defaults to ``auto``. Known values are: "auto" and "none". + :vartype target_response: str or ~azure.ai.projects.models.VoiceAgentHandoffTargetResponse """ - type: Union[str, "_models.VoiceAgentAvatarType"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The handoff condition identifier. Required.""" + target: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target subagent identifier or ``$entrypoint``. The containing subagent supplies the source. + Required.""" + condition: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Natural-language routing guidance supplied alongside the active subagent instructions, from 1 + through 500 characters. This is not an executable Boolean predicate. Required.""" + cancel_on_interruption: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether user interruption before commit cancels the pending handoff. If omitted, the service + defaults to false.""" + delay_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" ) - """The avatar type. Required. Known values are: \"video_avatar\" and \"photo_avatar\".""" - character: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The avatar character identifier, e.g. 'lisa'. Required.""" - style: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The avatar style, e.g. 'casual-sitting'.""" - customized: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the avatar is a customer-customized avatar. Defaults to false.""" - output_protocol: Optional[Union[str, "_models.VoiceAgentAvatarOutputProtocol"]] = rest_field( + """The minimum delay before target activation, in milliseconds, from 0 through 10000. If omitted, + the service defaults to 0.""" + transfer_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional deterministic source-voice announcement played before target activation. Supported by + cascaded pipelines and realtime pipelines using local Azure TTS; model-native realtime voice + requires omission or null. At most 500 characters. If omitted or null, no announcement is + played.""" + target_response: Optional[Union[str, "_models.VoiceAgentHandoffTargetResponse"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The transport used to deliver the avatar video stream. Known values are: \"webrtc\" and - \"websocket\".""" - model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The avatar model identifier.""" - video: Optional["_models.VoiceAgentAvatarVideoParams"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + """Whether Voice Live automatically starts a response after target activation. If omitted, the + service defaults to ``auto``. Known values are: \"auto\" and \"none\".""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + target: str, + condition: str, + cancel_on_interruption: Optional[bool] = None, + delay_ms: Optional[datetime.timedelta] = None, + transfer_message: Optional[str] = None, + target_response: Optional[Union[str, "_models.VoiceAgentHandoffTargetResponse"]] = 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 VoiceAgentHandoffEdgeState(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Non-sensitive topology metadata for one compiled handoff edge. + + :ivar id: The edge identifier. Required. + :vartype id: str + :ivar source: The source node identifier or ``$entrypoint``. Required. + :vartype source: str + :ivar target: The target node identifier or ``$entrypoint``. Required. + :vartype target: str + :ivar cancel_on_interruption: Whether user interruption before commit cancels the pending + handoff. + :vartype cancel_on_interruption: bool + :ivar delay_ms: The minimum delay before target activation, in milliseconds. + :vartype delay_ms: ~datetime.timedelta + :ivar transfer_message: The deterministic source-voice announcement played before target + activation. + :vartype transfer_message: str + :ivar target_response: Whether Voice Live automatically starts a response after target + activation. Known values are: "auto" and "none". + :vartype target_response: str or ~azure.ai.projects.models.VoiceAgentHandoffTargetResponse + """ + + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The edge identifier. Required.""" + source: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source node identifier or ``$entrypoint``. Required.""" + target: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target node identifier or ``$entrypoint``. Required.""" + cancel_on_interruption: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether user interruption before commit cancels the pending handoff.""" + delay_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" ) - """Avatar video encoder and presentation settings.""" - scene: Optional["_models.VoiceAgentAvatarScene"] = rest_field( + """The minimum delay before target activation, in milliseconds.""" + transfer_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The deterministic source-voice announcement played before target activation.""" + target_response: Optional[Union[str, "_models.VoiceAgentHandoffTargetResponse"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Avatar placement and motion settings.""" - output_audit_audio: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether audit audio is emitted with avatar output. Defaults to false.""" + """Whether Voice Live automatically starts a response after target activation. Known values are: + \"auto\" and \"none\".""" @overload def __init__( self, *, - type: Union[str, "_models.VoiceAgentAvatarType"], - character: str, - style: Optional[str] = None, - customized: Optional[bool] = None, - output_protocol: Optional[Union[str, "_models.VoiceAgentAvatarOutputProtocol"]] = None, - model: Optional[str] = None, - video: Optional["_models.VoiceAgentAvatarVideoParams"] = None, - scene: Optional["_models.VoiceAgentAvatarScene"] = None, - output_audit_audio: Optional[bool] = None, + id: str, # pylint: disable=redefined-builtin + source: str, + target: str, + cancel_on_interruption: Optional[bool] = None, + delay_ms: Optional[datetime.timedelta] = None, + transfer_message: Optional[str] = None, + target_response: Optional[Union[str, "_models.VoiceAgentHandoffTargetResponse"]] = None, ) -> None: ... @overload @@ -28057,29 +37873,34 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAvatarIceServer(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """An ICE server used for avatar WebRTC negotiation. +class VoiceAgentHandoffNodeState(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Non-sensitive topology metadata for one compiled handoff node. - :ivar urls: Required. - :vartype urls: list[str] - :ivar username: - :vartype username: str - :ivar credential: - :vartype credential: str + :ivar id: The node identifier or ``$entrypoint``. Required. + :vartype id: str + :ivar display_description: The display-only node description. This value is not provided to the + model. Required. + :vartype display_description: str + :ivar implicit: Whether this is the implicit ``$entrypoint`` node. + :vartype implicit: bool """ - urls: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - username: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - credential: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The node identifier or ``$entrypoint``. Required.""" + display_description: str = rest_field( + name="description", visibility=["read", "create", "update", "delete", "query"] + ) + """The display-only node description. This value is not provided to the model. Required.""" + implicit: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether this is the implicit ``$entrypoint`` node.""" @overload def __init__( self, *, - urls: list[str], - username: Optional[str] = None, - credential: Optional[str] = None, + id: str, # pylint: disable=redefined-builtin + display_description: str, + implicit: Optional[bool] = None, ) -> None: ... @overload @@ -28093,44 +37914,32 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAvatarScene(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Avatar placement and motion settings. +class VoiceAgentHandoffPolicy(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Session-wide limits shared by all handoff conditions in one Voice Agent session. - :ivar zoom: - :vartype zoom: float - :ivar position_x: - :vartype position_x: float - :ivar position_y: - :vartype position_y: float - :ivar rotation_x: - :vartype rotation_x: float - :ivar rotation_y: - :vartype rotation_y: float - :ivar rotation_z: - :vartype rotation_z: float - :ivar amplitude: - :vartype amplitude: float + :ivar max_transfers: The maximum number of successfully completed handoffs in one session, from + 1 through 100. If omitted, the service defaults to 16. + :vartype max_transfers: int + :ivar max_attempts: The maximum number of attempted handoffs, from 1 through 100. If omitted, + the service uses ``max_transfers``. The service requires this value to be greater than or equal + to ``max_transfers``. + :vartype max_attempts: int """ - zoom: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - position_x: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - position_y: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - rotation_x: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - rotation_y: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - rotation_z: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - amplitude: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + max_transfers: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The maximum number of successfully completed handoffs in one session, from 1 through 100. If + omitted, the service defaults to 16.""" + max_attempts: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The maximum number of attempted handoffs, from 1 through 100. If omitted, the service uses + ``max_transfers``. The service requires this value to be greater than or equal to + ``max_transfers``.""" @overload def __init__( self, *, - zoom: Optional[float] = None, - position_x: Optional[float] = None, - position_y: Optional[float] = None, - rotation_x: Optional[float] = None, - rotation_y: Optional[float] = None, - rotation_z: Optional[float] = None, - amplitude: Optional[float] = None, + max_transfers: Optional[int] = None, + max_attempts: Optional[int] = None, ) -> None: ... @overload @@ -28144,24 +37953,76 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAvatarVideoBackground(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The avatar video background. +class VoiceAgentHandoffState(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The effective topology and runtime state of a voice-agent handoff graph. - :ivar image_url: - :vartype image_url: str - :ivar color: - :vartype color: str + :ivar pipeline_family: The immutable execution pipeline family. Required. Known values are: + "cascaded" and "realtime". + :vartype pipeline_family: str or ~azure.ai.projects.models.VoiceAgentHandoffPipelineFamily + :ivar active_node_id: The currently committed node identifier or ``$entrypoint``. Required. + :vartype active_node_id: str + :ivar node_generation: The monotonically increasing generation of the committed active-node + configuration. Required. + :vartype node_generation: int + :ivar transfer_count: The number of successfully completed handoffs. Required. + :vartype transfer_count: int + :ivar attempt_count: The number of unique reserved handoff attempts. Required. + :vartype attempt_count: int + :ivar available_edge_ids: The edge identifiers currently available from the active node. + Required. + :vartype available_edge_ids: list[str] + :ivar transfer_tool: The generated handoff function visible to the active model, or null when + no route is available. Required. + :vartype transfer_tool: ~azure.ai.projects.models.VoiceAgentFunctionTool + :ivar nodes: The compiled handoff nodes, including the implicit or explicit ``$entrypoint``. + Required. + :vartype nodes: list[~azure.ai.projects.models.VoiceAgentHandoffNodeState] + :ivar edges: The compiled handoff edges. Required. + :vartype edges: list[~azure.ai.projects.models.VoiceAgentHandoffEdgeState] """ - image_url: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - color: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + pipeline_family: Union[str, "_models.VoiceAgentHandoffPipelineFamily"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The immutable execution pipeline family. Required. Known values are: \"cascaded\" and + \"realtime\".""" + active_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The currently committed node identifier or ``$entrypoint``. Required.""" + node_generation: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The monotonically increasing generation of the committed active-node configuration. Required.""" + transfer_count: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of successfully completed handoffs. Required.""" + attempt_count: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of unique reserved handoff attempts. Required.""" + available_edge_ids: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The edge identifiers currently available from the active node. Required.""" + transfer_tool: "_models.VoiceAgentFunctionTool" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The generated handoff function visible to the active model, or null when no route is available. + Required.""" + nodes: list["_models.VoiceAgentHandoffNodeState"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The compiled handoff nodes, including the implicit or explicit ``$entrypoint``. Required.""" + edges: list["_models.VoiceAgentHandoffEdgeState"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The compiled handoff edges. Required.""" @overload def __init__( self, *, - image_url: Optional[str] = None, - color: Optional[str] = None, + pipeline_family: Union[str, "_models.VoiceAgentHandoffPipelineFamily"], + active_node_id: str, + node_generation: int, + transfer_count: int, + attempt_count: int, + available_edge_ids: list[str], + transfer_tool: "_models.VoiceAgentFunctionTool", + nodes: list["_models.VoiceAgentHandoffNodeState"], + edges: list["_models.VoiceAgentHandoffEdgeState"], ) -> None: ... @overload @@ -28175,26 +38036,64 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAvatarVideoCrop(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The rectangular crop applied to avatar video. +class VoiceAgentHandoffVoiceAdaptation(_Model): # pylint: disable=docstring-missing-param + """Voice-optimized instruction adaptation applied while a handoff node is active. - :ivar bottom_right: Required. - :vartype bottom_right: list[int] - :ivar top_left: Required. - :vartype top_left: list[int] + :ivar type: The adaptation strategy. Currently only ``auto`` is supported. Required. Default + value is "auto". + :vartype type: str """ - bottom_right: list[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - top_left: list[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + type: Literal["auto"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The adaptation strategy. Currently only ``auto`` is supported. Required. Default value is + \"auto\".""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["auto"] = "auto" + + +class VoiceAgentInlineSubagentConfig( + VoiceAgentSubagentConfig, discriminator="inline" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Configuration for inline voice subagents that may become active through Handoff. + + :ivar subagent_type: The subagent mode for inline voice subagents. Required. Inline voice + behaviors that may become active through Handoff. + :vartype subagent_type: str or ~azure.ai.projects.models.INLINE + :ivar subagents: Inline voice subagents owned and versioned with the parent Voice Agent. + ``$entrypoint`` must be first, followed by at least one specialist and at most 31 additional + subagents. Each subagent declares its outgoing ``handoff_conditions``; condition identifiers + and the 128-condition limit apply across the entire Agent. Required. + :vartype subagents: list[~azure.ai.projects.models.InlineVoiceSubagent] + :ivar handoff_policy: Session-wide Handoff limits. Requires ``$entrypoint`` with at least one + outgoing condition. When omitted, the service permits up to 16 completed and 16 attempted + handoffs. + :vartype handoff_policy: ~azure.ai.projects.models.VoiceAgentHandoffPolicy + """ + + subagent_type: Literal[VoiceAgentSubagentType.INLINE] = rest_discriminator(name="subagent_type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The subagent mode for inline voice subagents. Required. Inline voice behaviors that may become + active through Handoff.""" + subagents: list["_models.InlineVoiceSubagent"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Inline voice subagents owned and versioned with the parent Voice Agent. ``$entrypoint`` must be + first, followed by at least one specialist and at most 31 additional subagents. Each subagent + declares its outgoing ``handoff_conditions``; condition identifiers and the 128-condition limit + apply across the entire Agent. Required.""" + handoff_policy: Optional["_models.VoiceAgentHandoffPolicy"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Session-wide Handoff limits. Requires ``$entrypoint`` with at least one outgoing condition. + When omitted, the service permits up to 16 completed and 16 attempted handoffs.""" @overload def __init__( self, *, - bottom_right: list[int], - top_left: list[int], + subagents: list["_models.InlineVoiceSubagent"], + handoff_policy: Optional["_models.VoiceAgentHandoffPolicy"] = None, ) -> None: ... @overload @@ -28206,45 +38105,131 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.subagent_type = VoiceAgentSubagentType.INLINE # type: ignore -class VoiceAgentAvatarVideoParams(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Avatar video encoder and presentation settings. +class VoiceAgentInputTranscription(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Settings for transcribing input audio, including the transcription model, Custom Speech + deployments, and phrase hints. When ``model`` is ``azure-speech-streaming``, transcription is + supported for cascaded text-model conversations only (not realtime speech-to-speech models), + requires a nonempty ``language`` such as ``en-US`` (comma-separated locales are supported), and + supports ``custom_speech``, ``phrase_list``, and ``profanity_filter``. - :ivar bitrate: The target video bitrate in bits per second. - :vartype bitrate: int - :ivar crop: - :vartype crop: ~azure.ai.projects.models.VoiceAgentAvatarVideoCrop - :ivar resolution: - :vartype resolution: ~azure.ai.projects.models.VoiceAgentAvatarVideoResolution - :ivar background: - :vartype background: ~azure.ai.projects.models.VoiceAgentAvatarVideoBackground - :ivar gop_size: - :vartype gop_size: int + :ivar language: The language of the input audio. Supplying the input language in `ISO-639-1 + `_ (e.g. ``en``) format will improve + accuracy and latency. Optional for other transcription models; required and must be nonempty + when ``model`` is ``azure-speech-streaming`` (such as ``en-US``; comma-separated locales are + supported). + :vartype language: str + :ivar languages: Possible languages of the input audio, in `ISO-639-1 + `_ format. Supported by + ``gpt-transcribe`` and ``gpt-live-transcribe``. + :vartype languages: list[str] + :ivar keywords: Words or phrases to guide transcription of the input audio. Supported by + ``gpt-transcribe`` and ``gpt-live-transcribe``. + :vartype keywords: list[str] + :ivar prompt: An optional text to guide the model's style or continue a previous audio segment. + For ``whisper-1``, the `prompt is a list of keywords + `_. For + ``gpt-4o-transcribe`` models (excluding ``gpt-4o-transcribe-diarize``), the prompt is a free + text string, for example "expect words related to technology". Prompt is not supported with + ``gpt-realtime-whisper`` in GA Realtime sessions. + :vartype prompt: str + :ivar delay: Controls how long the model waits before emitting transcription text. Higher + values can improve transcription accuracy at the cost of latency. Only supported with + ``gpt-realtime-whisper`` in GA Realtime sessions. Is one of the following types: + Literal["minimal"], Literal["low"], Literal["medium"], Literal["high"], Literal["xhigh"] + :vartype delay: str or str or str or str or str + :ivar model: The transcription model identifier. Configure customer custom speech deployments + in ``custom_speech``. ``azure-speech-streaming`` is for cascaded text-model conversations only + (not realtime speech-to-speech models), requires a nonempty ``language`` such as ``en-US`` + (comma-separated locales are supported), and supports ``custom_speech``, ``phrase_list``, and + ``profanity_filter``. Required. Known values are: "whisper-1", "gpt-realtime-whisper", + "gpt-4o-transcribe", "gpt-4o-mini-transcribe", "gpt-4o-transcribe-diarize", "gpt-transcribe", + "gpt-live-transcribe", "mai-transcribe", "azure-speech", and "azure-speech-streaming". + :vartype model: str or ~azure.ai.projects.models.VoiceAgentInputTranscriptionModel + :ivar custom_speech: Optional customer custom speech deployment configuration, keyed by locale. + :vartype custom_speech: dict[str, str] + :ivar phrase_list: Optional phrase hints that bias recognition toward domain terms. + :vartype phrase_list: list[str] + :ivar profanity_filter: Controls how profanity is handled in input transcripts. Supported only + with managed Azure Speech (``azure-speech`` and ``azure-speech-streaming``), including Custom + Speech. Set this property before the session starts. If omitted, the transcription provider's + default applies. You cannot change the mode during a session. Filtering affects transcript + events and the text sent to cascaded models. It does not change input audio, voice activity + detection, or assistant speech; audio-native models still receive the original audio. Mandatory + service masking policies apply even when you select ``unfiltered``. Known values are: "masked", + "unfiltered", and "removed". + :vartype profanity_filter: str or ~azure.ai.projects.models.VoiceAgentProfanityFilterMode """ - bitrate: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The target video bitrate in bits per second.""" - crop: Optional["_models.VoiceAgentAvatarVideoCrop"] = rest_field( + language: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The language of the input audio. Supplying the input language in `ISO-639-1 + `_ (e.g. ``en``) format will improve + accuracy and latency. Optional for other transcription models; required and must be nonempty + when ``model`` is ``azure-speech-streaming`` (such as ``en-US``; comma-separated locales are + supported).""" + languages: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Possible languages of the input audio, in `ISO-639-1 + `_ format. Supported by + ``gpt-transcribe`` and ``gpt-live-transcribe``.""" + keywords: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Words or phrases to guide transcription of the input audio. Supported by ``gpt-transcribe`` and + ``gpt-live-transcribe``.""" + prompt: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional text to guide the model's style or continue a previous audio segment. For + ``whisper-1``, the `prompt is a list of keywords + `_. For + ``gpt-4o-transcribe`` models (excluding ``gpt-4o-transcribe-diarize``), the prompt is a free + text string, for example \"expect words related to technology\". Prompt is not supported with + ``gpt-realtime-whisper`` in GA Realtime sessions.""" + delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - resolution: Optional["_models.VoiceAgentAvatarVideoResolution"] = rest_field( + """Controls how long the model waits before emitting transcription text. Higher values can improve + transcription accuracy at the cost of latency. Only supported with ``gpt-realtime-whisper`` in + GA Realtime sessions. Is one of the following types: Literal[\"minimal\"], Literal[\"low\"], + Literal[\"medium\"], Literal[\"high\"], Literal[\"xhigh\"]""" + model: Union[str, "_models.VoiceAgentInputTranscriptionModel"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - background: Optional["_models.VoiceAgentAvatarVideoBackground"] = rest_field( + """The transcription model identifier. Configure customer custom speech deployments in + ``custom_speech``. ``azure-speech-streaming`` is for cascaded text-model conversations only + (not realtime speech-to-speech models), requires a nonempty ``language`` such as ``en-US`` + (comma-separated locales are supported), and supports ``custom_speech``, ``phrase_list``, and + ``profanity_filter``. Required. Known values are: \"whisper-1\", \"gpt-realtime-whisper\", + \"gpt-4o-transcribe\", \"gpt-4o-mini-transcribe\", \"gpt-4o-transcribe-diarize\", + \"gpt-transcribe\", \"gpt-live-transcribe\", \"mai-transcribe\", \"azure-speech\", and + \"azure-speech-streaming\".""" + custom_speech: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional customer custom speech deployment configuration, keyed by locale.""" + phrase_list: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional phrase hints that bias recognition toward domain terms.""" + profanity_filter: Optional[Union[str, "_models.VoiceAgentProfanityFilterMode"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - gop_size: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Controls how profanity is handled in input transcripts. Supported only with managed Azure + Speech (``azure-speech`` and ``azure-speech-streaming``), including Custom Speech. Set this + property before the session starts. If omitted, the transcription provider's default applies. + You cannot change the mode during a session. Filtering affects transcript events and the text + sent to cascaded models. It does not change input audio, voice activity detection, or assistant + speech; audio-native models still receive the original audio. Mandatory service masking + policies apply even when you select ``unfiltered``. Known values are: \"masked\", + \"unfiltered\", and \"removed\".""" @overload def __init__( self, *, - bitrate: Optional[int] = None, - crop: Optional["_models.VoiceAgentAvatarVideoCrop"] = None, - resolution: Optional["_models.VoiceAgentAvatarVideoResolution"] = None, - background: Optional["_models.VoiceAgentAvatarVideoBackground"] = None, - gop_size: Optional[int] = None, + model: Union[str, "_models.VoiceAgentInputTranscriptionModel"], + language: Optional[str] = None, + languages: Optional[list[str]] = None, + keywords: Optional[list[str]] = None, + prompt: Optional[str] = None, + delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] = None, + custom_speech: Optional[dict[str, str]] = None, + phrase_list: Optional[list[str]] = None, + profanity_filter: Optional[Union[str, "_models.VoiceAgentProfanityFilterMode"]] = None, ) -> None: ... @overload @@ -28258,26 +38243,41 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentAvatarVideoResolution(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The avatar video resolution. +class VoiceAgentInterimResponseConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Fields shared by interim-response configurations. - :ivar width: Required. - :vartype width: int - :ivar height: Required. - :vartype height: int + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentLlmInterimResponseConfig, VoiceAgentStaticInterimResponseConfig + + :ivar type: The interim-response implementation. Required. Known values are: + "static_interim_response" and "llm_interim_response". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentInterimResponseType + :ivar triggers: Conditions that may trigger one interim response. + :vartype triggers: list[str or ~azure.ai.projects.models.VoiceAgentInterimResponseTrigger] + :ivar latency_threshold_ms: The latency threshold in milliseconds. + :vartype latency_threshold_ms: ~datetime.timedelta """ - width: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - height: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The interim-response implementation. Required. Known values are: \"static_interim_response\" + and \"llm_interim_response\".""" + triggers: Optional[list[Union[str, "_models.VoiceAgentInterimResponseTrigger"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Conditions that may trigger one interim response.""" + latency_threshold_ms: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """The latency threshold in milliseconds.""" @overload def __init__( self, *, - width: int, - height: int, + type: str, + triggers: Optional[list[Union[str, "_models.VoiceAgentInterimResponseTrigger"]]] = None, + latency_threshold_ms: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -28291,36 +38291,69 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentTurnDetectionConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Turn-detection configuration for a voice agent. +class VoiceAgentLanguageDetectionArguments(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Decoded model-generated language-switch arguments, not a new client ingress. Unsupported speech + components do not gain language support from this tool. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - VoiceAgentAzureSemanticVadTurnDetection, VoiceAgentAzureSemanticVadEnTurnDetection, - VoiceAgentAzureSemanticVadMultilingualTurnDetection, VoiceAgentSemanticVadTurnDetection, - VoiceAgentServerVadTurnDetection + :ivar language: Target language in lowercase ISO 639-1 format, such as es or fr. Required. + :vartype language: str + :ivar reason: Non-blank reason for switching the conversation language. Required. + :vartype reason: str + """ - :ivar type: The turn-detection strategy. Required. Known values are: "server_vad", - "semantic_vad", "azure_semantic_vad", "azure_semantic_vad_en", and - "azure_semantic_vad_multilingual". - :vartype type: str or ~azure.ai.projects.models.VoiceAgentTurnDetectionType - :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech - stops. - :vartype auto_truncate: bool + language: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Target language in lowercase ISO 639-1 format, such as es or fr. Required.""" + reason: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Non-blank reason for switching the conversation language. Required.""" + + @overload + def __init__( + self, + *, + language: str, + reason: 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 VoiceAgentLanguageDetectionSystemTool( + VoiceAgentSystemTool, discriminator="language_detection" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Switches supported conversation language settings. + + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``language_detection``. Required. + Switches supported conversation language settings. + :vartype name: str or ~azure.ai.projects.models.LANGUAGE_DETECTION """ __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The turn-detection strategy. Required. Known values are: \"server_vad\", \"semantic_vad\", - \"azure_semantic_vad\", \"azure_semantic_vad_en\", and \"azure_semantic_vad_multilingual\".""" - auto_truncate: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the input audio buffer is truncated automatically when speech stops.""" + name: Literal[VoiceAgentSystemToolName.LANGUAGE_DETECTION] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``language_detection``. Required. Switches supported + conversation language settings.""" @overload def __init__( self, *, - type: str, - auto_truncate: Optional[bool] = None, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, ) -> None: ... @overload @@ -28332,86 +38365,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.name = VoiceAgentSystemToolName.LANGUAGE_DETECTION # type: ignore -class VoiceAgentAzureSemanticVadEnTurnDetection( - VoiceAgentTurnDetectionConfig, discriminator="azure_semantic_vad_en" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """English-optimized Azure semantic voice activity detection. +class VoiceAgentLiveDelegation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Who handles delegated work for a Live voice agent. - :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech - stops. - :vartype auto_truncate: bool - :ivar type: Required. English-optimized Azure semantic voice activity detection. - :vartype type: str or ~azure.ai.projects.models.AZURE_SEMANTIC_VAD_EN - :ivar threshold: Activation threshold for voice activity detection, from 0 to 1. - :vartype threshold: float - :ivar prefix_padding_ms: Audio to include before detected speech, in milliseconds. - :vartype prefix_padding_ms: ~datetime.timedelta - :ivar silence_duration_ms: Silence required to end speech detection, in milliseconds. - :vartype silence_duration_ms: ~datetime.timedelta - :ivar idle_timeout_ms: Maximum idle time before the detector ends the turn, in milliseconds. - :vartype idle_timeout_ms: ~datetime.timedelta - :ivar end_of_utterance_detection: Semantic end-of-utterance detection configuration. Set to - null to disable it. - :vartype end_of_utterance_detection: - ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection - :ivar speech_duration_ms: Minimum speech duration required to trigger detection, in - milliseconds. - :vartype speech_duration_ms: ~datetime.timedelta - :ivar remove_filler_words: Whether filler words are removed from transcription. - :vartype remove_filler_words: bool - :ivar create_response: Whether a response is created automatically when speech stops. - :vartype create_response: bool - :ivar interrupt_response: Whether user speech may interrupt the agent's response. - :vartype interrupt_response: bool + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentLiveClientDelegation, VoiceAgentLiveManagedAgentDelegation, + VoiceAgentLiveResponsesDelegation + + :ivar type: The delegation owner. Required. Known values are: "client", "responses", and + "foundry_managed_agent". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentLiveDelegationType """ - type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_EN] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. English-optimized Azure semantic voice activity detection.""" - threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Activation threshold for voice activity detection, from 0 to 1.""" - prefix_padding_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Audio to include before detected speech, in milliseconds.""" - silence_duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Silence required to end speech detection, in milliseconds.""" - idle_timeout_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Maximum idle time before the detector ends the turn, in milliseconds.""" - end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Semantic end-of-utterance detection configuration. Set to null to disable it.""" - speech_duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Minimum speech duration required to trigger detection, in milliseconds.""" - remove_filler_words: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether filler words are removed from transcription.""" - create_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether a response is created automatically when speech stops.""" - interrupt_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether user speech may interrupt the agent's response.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The delegation owner. Required. Known values are: \"client\", \"responses\", and + \"foundry_managed_agent\".""" @overload def __init__( self, - *, - auto_truncate: Optional[bool] = None, - threshold: Optional[float] = None, - prefix_padding_ms: Optional[datetime.timedelta] = None, - silence_duration_ms: Optional[datetime.timedelta] = None, - idle_timeout_ms: Optional[datetime.timedelta] = None, - end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = None, - speech_duration_ms: Optional[datetime.timedelta] = None, - remove_filler_words: Optional[bool] = None, - create_response: Optional[bool] = None, - interrupt_response: Optional[bool] = None, + *, + type: str, ) -> None: ... @overload @@ -28423,92 +38401,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_EN # type: ignore -class VoiceAgentAzureSemanticVadMultilingualTurnDetection( - VoiceAgentTurnDetectionConfig, discriminator="azure_semantic_vad_multilingual" -): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """Multilingual Azure semantic voice activity detection. +class VoiceAgentLiveClientDelegation( + VoiceAgentLiveDelegation, discriminator="client" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Delegates work to the application using native client delegation. - :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech - stops. - :vartype auto_truncate: bool - :ivar type: Required. Multilingual Azure semantic voice activity detection. - :vartype type: str or ~azure.ai.projects.models.AZURE_SEMANTIC_VAD_MULTILINGUAL - :ivar threshold: Activation threshold for voice activity detection, from 0 to 1. - :vartype threshold: float - :ivar prefix_padding_ms: Audio to include before detected speech, in milliseconds. - :vartype prefix_padding_ms: ~datetime.timedelta - :ivar silence_duration_ms: Silence required to end speech detection, in milliseconds. - :vartype silence_duration_ms: ~datetime.timedelta - :ivar idle_timeout_ms: Maximum idle time before the detector ends the turn, in milliseconds. - :vartype idle_timeout_ms: ~datetime.timedelta - :ivar end_of_utterance_detection: Semantic end-of-utterance detection configuration. Set to - null to disable it. - :vartype end_of_utterance_detection: - ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection - :ivar speech_duration_ms: Minimum speech duration required to trigger detection, in - milliseconds. - :vartype speech_duration_ms: ~datetime.timedelta - :ivar remove_filler_words: Whether filler words are removed from transcription. - :vartype remove_filler_words: bool - :ivar create_response: Whether a response is created automatically when speech stops. - :vartype create_response: bool - :ivar interrupt_response: Whether user speech may interrupt the agent's response. - :vartype interrupt_response: bool - :ivar languages: BCP-47 language codes used for speech detection. - :vartype languages: list[str] + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar type: Required. The application handles delegated work. + :vartype type: str or ~azure.ai.projects.models.CLIENT """ - type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_MULTILINGUAL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Multilingual Azure semantic voice activity detection.""" - threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Activation threshold for voice activity detection, from 0 to 1.""" - prefix_padding_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Audio to include before detected speech, in milliseconds.""" - silence_duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Silence required to end speech detection, in milliseconds.""" - idle_timeout_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Maximum idle time before the detector ends the turn, in milliseconds.""" - end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Semantic end-of-utterance detection configuration. Set to null to disable it.""" - speech_duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Minimum speech duration required to trigger detection, in milliseconds.""" - remove_filler_words: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether filler words are removed from transcription.""" - create_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether a response is created automatically when speech stops.""" - interrupt_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether user speech may interrupt the agent's response.""" - languages: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """BCP-47 language codes used for speech detection.""" + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + type: Literal[VoiceAgentLiveDelegationType.CLIENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. The application handles delegated work.""" @overload def __init__( self, *, - auto_truncate: Optional[bool] = None, - threshold: Optional[float] = None, - prefix_padding_ms: Optional[datetime.timedelta] = None, - silence_duration_ms: Optional[datetime.timedelta] = None, - idle_timeout_ms: Optional[datetime.timedelta] = None, - end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = None, - speech_duration_ms: Optional[datetime.timedelta] = None, - remove_filler_words: Optional[bool] = None, - create_response: Optional[bool] = None, - interrupt_response: Optional[bool] = None, - languages: Optional[list[str]] = None, + acknowledgement_delay_ms: Optional[int] = None, ) -> None: ... @overload @@ -28520,92 +38444,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD_MULTILINGUAL # type: ignore + self.type = VoiceAgentLiveDelegationType.CLIENT # type: ignore -class VoiceAgentAzureSemanticVadTurnDetection( - VoiceAgentTurnDetectionConfig, discriminator="azure_semantic_vad" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """Azure semantic voice activity detection. +class VoiceAgentLiveConversationItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A stored speech segment or delegation. Speech segments are not native turns or proof of + playback; delegation results are separate from spoken transcripts. - :ivar auto_truncate: Whether the input audio buffer is truncated automatically when speech - stops. - :vartype auto_truncate: bool - :ivar type: Required. Azure semantic voice activity detection. - :vartype type: str or ~azure.ai.projects.models.AZURE_SEMANTIC_VAD - :ivar threshold: Activation threshold for voice activity detection, from 0 to 1. - :vartype threshold: float - :ivar prefix_padding_ms: Audio to include before detected speech, in milliseconds. - :vartype prefix_padding_ms: ~datetime.timedelta - :ivar silence_duration_ms: Silence required to end speech detection, in milliseconds. - :vartype silence_duration_ms: ~datetime.timedelta - :ivar idle_timeout_ms: Maximum idle time before the detector ends the turn, in milliseconds. - :vartype idle_timeout_ms: ~datetime.timedelta - :ivar end_of_utterance_detection: Semantic end-of-utterance detection configuration. Set to - null to disable it. - :vartype end_of_utterance_detection: - ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetection - :ivar speech_duration_ms: Minimum speech duration required to trigger detection, in - milliseconds. - :vartype speech_duration_ms: ~datetime.timedelta - :ivar remove_filler_words: Whether filler words are removed from transcription. - :vartype remove_filler_words: bool - :ivar create_response: Whether a response is created automatically when speech stops. - :vartype create_response: bool - :ivar interrupt_response: Whether user speech may interrupt the agent's response. - :vartype interrupt_response: bool - :ivar languages: BCP-47 language codes used for speech detection. - :vartype languages: list[str] + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentLiveDelegationConversationItem, VoiceAgentLiveInputConversationItem, + VoiceAgentLiveOutputConversationItem + + :ivar type: The persisted item kind. Required. Known values are: "input", "output", and + "delegation". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentLiveConversationItemType + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str """ - type: Literal[VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Azure semantic voice activity detection.""" - threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Activation threshold for voice activity detection, from 0 to 1.""" - prefix_padding_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Audio to include before detected speech, in milliseconds.""" - silence_duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Silence required to end speech detection, in milliseconds.""" - idle_timeout_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Maximum idle time before the detector ends the turn, in milliseconds.""" - end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Semantic end-of-utterance detection configuration. Set to null to disable it.""" - speech_duration_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """Minimum speech duration required to trigger detection, in milliseconds.""" - remove_filler_words: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether filler words are removed from transcription.""" - create_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether a response is created automatically when speech stops.""" - interrupt_response: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether user speech may interrupt the agent's response.""" - languages: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """BCP-47 language codes used for speech detection.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The persisted item kind. Required. Known values are: \"input\", \"output\", and \"delegation\".""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their native + value. Required.""" @overload def __init__( self, *, - auto_truncate: Optional[bool] = None, - threshold: Optional[float] = None, - prefix_padding_ms: Optional[datetime.timedelta] = None, - silence_duration_ms: Optional[datetime.timedelta] = None, - idle_timeout_ms: Optional[datetime.timedelta] = None, - end_of_utterance_detection: Optional["_models.VoiceAgentEndOfUtteranceDetection"] = None, - speech_duration_ms: Optional[datetime.timedelta] = None, - remove_filler_words: Optional[bool] = None, - create_response: Optional[bool] = None, - interrupt_response: Optional[bool] = None, - languages: Optional[list[str]] = None, + type: str, + id: str, # pylint: disable=redefined-builtin ) -> None: ... @overload @@ -28617,44 +38487,56 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = VoiceAgentTurnDetectionType.AZURE_SEMANTIC_VAD # type: ignore -class VoiceAgentClientEventRtcCallSdpCreate( - RealtimeClientEvent, discriminator="rtc.call.sdp.create" +class VoiceAgentLiveDelegationConversationItem( + VoiceAgentLiveConversationItem, discriminator="delegation" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """The ``rtc.call.sdp.create`` client event: begins WebRTC signaling with an SDP offer. + """A stored delegation using native fields with Foundry-specific targets. Its id is the native + delegation ID. - :ivar type: The event type. Always ``rtc.call.sdp.create``. Required. RTC_CALL_SDP_CREATE. - :vartype type: str or ~azure.ai.projects.models.RTC_CALL_SDP_CREATE - :ivar event_id: An optional client-generated event identifier. - :vartype event_id: str - :ivar sdp_offer: The client's SDP offer for the WebRTC connection. Required. - :vartype sdp_offer: str - :ivar session: Optional session configuration. For an ``/agents`` endpoint the service rebuilds - it authoritatively from the persisted agent definition. - :vartype session: ~azure.ai.projects.models.VoiceAgentSessionUpdateConfig + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + VoiceAgentLiveClientDelegationConversationItem, + VoiceAgentLiveFoundryManagedAgentDelegationItem, + VoiceAgentLiveResponsesDelegationConversationItem + + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str + :ivar response_id: The ID of the Responses API response associated with a Responses delegation. + Omitted for client delegations. + :vartype response_id: str + :ivar type: Required. DELEGATION. + :vartype type: str or ~azure.ai.projects.models.DELEGATION + :ivar target: The configured delegation owner. Required. Known values are: "responses", + "client", and "foundry_managed_agent". + :vartype target: str or ~azure.ai.projects.models.VoiceAgentLiveDelegationTarget + :ivar created_at: Observed delegation creation time, in Unix seconds. Required. + :vartype created_at: ~datetime.datetime """ - type: Literal[RealtimeClientEventType.RTC_CALL_SDP_CREATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type. Always ``rtc.call.sdp.create``. Required. RTC_CALL_SDP_CREATE.""" - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional client-generated event identifier.""" - sdp_offer: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The client's SDP offer for the WebRTC connection. Required.""" - session: Optional["_models.VoiceAgentSessionUpdateConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + __mapping__: dict[str, _Model] = {} + response_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the Responses API response associated with a Responses delegation. Omitted for client + delegations.""" + type: Literal[VoiceAgentLiveConversationItemType.DELEGATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. DELEGATION.""" + target: str = rest_discriminator(name="target", visibility=["read", "create", "update", "delete", "query"]) + """The configured delegation owner. Required. Known values are: \"responses\", \"client\", and + \"foundry_managed_agent\".""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" ) - """Optional session configuration. For an ``/agents`` endpoint the service rebuilds it - authoritatively from the persisted agent definition.""" + """Observed delegation creation time, in Unix seconds. Required.""" @overload def __init__( self, *, - sdp_offer: str, - event_id: Optional[str] = None, - session: Optional["_models.VoiceAgentSessionUpdateConfig"] = None, + id: str, # pylint: disable=redefined-builtin + target: str, + created_at: datetime.datetime, + response_id: Optional[str] = None, ) -> None: ... @overload @@ -28666,36 +38548,49 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.RTC_CALL_SDP_CREATE # type: ignore + self.type = VoiceAgentLiveConversationItemType.DELEGATION # type: ignore -class VoiceAgentClientEventSessionAvatarConnect( - RealtimeClientEvent, discriminator="session.avatar.connect" +class VoiceAgentLiveClientDelegationConversationItem( + VoiceAgentLiveDelegationConversationItem, discriminator="client" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only - """The ``session.avatar.connect`` client event. + """Results supplied by the application for client delegation. - :ivar type: The event type. Always ``session.avatar.connect``. Required. - SESSION_AVATAR_CONNECT. - :vartype type: str or ~azure.ai.projects.models.SESSION_AVATAR_CONNECT - :ivar event_id: An optional client-generated event identifier. - :vartype event_id: str - :ivar client_sdp: The client's SDP offer for avatar media negotiation. Required. - :vartype client_sdp: str + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str + :ivar response_id: The ID of the Responses API response associated with a Responses delegation. + Omitted for client delegations. + :vartype response_id: str + :ivar type: Required. DELEGATION. + :vartype type: str or ~azure.ai.projects.models.DELEGATION + :ivar created_at: Observed delegation creation time, in Unix seconds. Required. + :vartype created_at: ~datetime.datetime + :ivar target: Required. CLIENT. + :vartype target: str or ~azure.ai.projects.models.CLIENT + :ivar commentary: Guidance for Live to communicate to the user, when accepted. + :vartype commentary: str + :ivar thinking: Accepted background context, not private reasoning or a request to speak. + :vartype thinking: str """ - type: Literal[RealtimeClientEventType.SESSION_AVATAR_CONNECT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The event type. Always ``session.avatar.connect``. Required. SESSION_AVATAR_CONNECT.""" - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional client-generated event identifier.""" - client_sdp: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The client's SDP offer for avatar media negotiation. Required.""" + __mapping__: dict[str, _Model] = {} + target: Literal[VoiceAgentLiveDelegationTarget.CLIENT] = rest_discriminator(name="target", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. CLIENT.""" + commentary: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Guidance for Live to communicate to the user, when accepted.""" + thinking: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Accepted background context, not private reasoning or a request to speak.""" @overload def __init__( self, *, - client_sdp: str, - event_id: Optional[str] = None, + id: str, # pylint: disable=redefined-builtin + created_at: datetime.datetime, + response_id: Optional[str] = None, + commentary: Optional[str] = None, + thinking: Optional[str] = None, ) -> None: ... @overload @@ -28707,42 +38602,77 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeClientEventType.SESSION_AVATAR_CONNECT # type: ignore + self.target = VoiceAgentLiveDelegationTarget.CLIENT # type: ignore -class VoiceAgentClientEventSessionUpdate(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """The ``session.update`` client event. +class VoiceAgentLiveConversation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A Live session persisted when effective store is true. Uses voice-conversation lifecycle and + retention; items are retrieved separately. - :ivar event_id: Optional client-generated ID used to identify this event. This is an arbitrary - string that a client may assign. It will be passed back if there is an error with the event, - but the corresponding ``session.updated`` event will not include it. - :vartype event_id: str - :ivar type: The event type, must be ``session.update``. Required. SESSION_UPDATE. - :vartype type: str or ~azure.ai.projects.models.SESSION_UPDATE - :ivar session: The voice-agent session settings to update. Required. Is one of the following - types: VoiceAgentSessionUpdateConfig - :vartype session: ~azure.ai.projects.models.VoiceAgentSessionUpdateConfig + :ivar id: The unique id of the conversation. Required. + :vartype id: str + :ivar object: The object type. Always ``voice.conversation``. Required. Default value is + "voice.conversation". + :vartype object: str + :ivar status: The lifecycle status of the conversation. Required. Known values are: + "in_progress", "completed", and "failed". + :vartype status: str or ~azure.ai.projects.models.VoiceConversationStatus + :ivar created_at: The Unix timestamp (in seconds) for when the conversation was created. + Required. + :vartype created_at: ~datetime.datetime + :ivar completed_at: The Unix timestamp (in seconds) for when session and persistence + finalization reached the terminal ``completed`` or ``failed`` status. Absent while ``status`` + is ``in_progress``. + :vartype completed_at: ~datetime.datetime + :ivar metadata: A set of key-value pairs attached to the conversation. + :vartype metadata: dict[str, str] + :ivar last_error: The terminal error that prevented persistence finalization. Present only when + ``status`` is ``failed``. + :vartype last_error: ~azure.ai.projects.models.ApiError + :ivar usage: Cumulative Live audio usage, excluding delegated-model tokens. May be absent after + abnormal close. + :vartype usage: ~azure.ai.projects.models.LiveSessionUsage """ - event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional client-generated ID used to identify this event. This is an arbitrary string that a - client may assign. It will be passed back if there is an error with the event, but the - corresponding ``session.updated`` event will not include it.""" - type: Literal[RealtimeClientEventType.SESSION_UPDATE] = rest_field( + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique id of the conversation. Required.""" + object: Literal["voice.conversation"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type. Always ``voice.conversation``. Required. Default value is + \"voice.conversation\".""" + status: Union[str, "_models.VoiceConversationStatus"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The event type, must be ``session.update``. Required. SESSION_UPDATE.""" - session: "_unions.VoiceAgentSessionUpdate" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The voice-agent session settings to update. Required. Is one of the following types: - VoiceAgentSessionUpdateConfig""" + """The lifecycle status of the conversation. Required. Known values are: \"in_progress\", + \"completed\", and \"failed\".""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when the conversation was created. Required.""" + completed_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The Unix timestamp (in seconds) for when session and persistence finalization reached the + terminal ``completed`` or ``failed`` status. Absent while ``status`` is ``in_progress``.""" + metadata: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A set of key-value pairs attached to the conversation.""" + last_error: Optional["_models.ApiError"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The terminal error that prevented persistence finalization. Present only when ``status`` is + ``failed``.""" + usage: Optional["_models.LiveSessionUsage"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Cumulative Live audio usage, excluding delegated-model tokens. May be absent after abnormal + close.""" @overload def __init__( self, *, - type: Literal[RealtimeClientEventType.SESSION_UPDATE], - session: "_unions.VoiceAgentSessionUpdate", - event_id: Optional[str] = None, + id: str, # pylint: disable=redefined-builtin + status: Union[str, "_models.VoiceConversationStatus"], + created_at: datetime.datetime, + completed_at: Optional[datetime.datetime] = None, + metadata: Optional[dict[str, str]] = None, + last_error: Optional["_models.ApiError"] = None, + usage: Optional["_models.LiveSessionUsage"] = None, ) -> None: ... @overload @@ -28754,221 +38684,85 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.object: Literal["voice.conversation"] = "voice.conversation" -class VoiceAgentDefinition( - AgentDefinition, discriminator="voice" +class VoiceAgentLiveDefinition( + VoiceAgentBaseDefinition, discriminator="live" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """The voice agent definition. Its configuration (model, instructions, audio, tools, and optional - avatar) drives a managed speech-to-speech experience. Establish realtime voice sessions through - ``GET /agents/{agent_name}/endpoint/protocols/voice``. Every create or update produces a new - immutable version. + """The Live voice agent definition. Its configuration (model, instructions, audio, and delegation) + drives a managed speech-to-speech experience using a Foundry GPT Live deployment. Establish + Live voice sessions through ``GET + /agents/{agent_name}/endpoint/protocols/voice/live/sessions``. Every create or update produces + a new immutable version. :ivar rai_config: Configuration for Responsible AI (RAI) content filtering and safety features. :vartype rai_config: ~azure.ai.projects.models.RaiConfig - :ivar kind: The kind discriminator for a voice agent definition. Always ``voice``. Required. - VOICE. + :ivar kind: Always voice. Required. VOICE. :vartype kind: str or ~azure.ai.projects.models.VOICE - :ivar model_type: How the model backing this voice agent is served. Required with ``model`` for - a model-backed voice agent and omitted when ``conversation_engine`` is provided. This is - independent of the architecture (realtime or cascaded), which the service derives from the - selected model. Known values are: "managed" and "self_deployed". - :vartype model_type: str or ~azure.ai.projects.models.VoiceModelType - :ivar model: The model to use for this agent. Required with ``model_type`` for a model-backed - voice agent and omitted when ``conversation_engine`` is provided. The model must support - realtime or cascaded voice. - :vartype model: str - :ivar conversation_engine: The engine that owns conversation handling for this voice agent. - Exactly one of this property and the model-backed configuration (``model_type`` with ``model``) - must be provided. When this property is provided, ``model_type``, ``model``, ``instructions``, - ``tools``, and ``tool_choice`` must be omitted, and ``greeting.tool_choice`` cannot be - ``required``, because the engine owns the conversation logic. The initial implementation - supports a hosted-agent engine. - :vartype conversation_engine: ~azure.ai.projects.models.VoiceConversationEngine - :ivar instructions: A system (or developer) message inserted into the model's context. Supports - template substitution via ``structured_inputs``, rendered per session before the live session - starts. + :ivar instructions: Frontend instructions, templated with structured_inputs. Backend + instructions belong in delegation.responses. :vartype instructions: str - :ivar greeting: Optional session-start greeting. Template mode speaks exact rendered text; - LLM-generated mode asks the session model to author the opening response and may use configured - tools. - :vartype greeting: ~azure.ai.projects.models.VoiceAgentGreetingConfig - :ivar audio: The audio configuration, including input and output formats, voice, turn - detection, noise reduction, and transcription. These values are session defaults; a client may - override supported fields when connecting. - :vartype audio: ~azure.ai.projects.models.VoiceAgentAudioConfig - :ivar soundscape: Optional background ambience and event cues, stored with the agent version - and separate from the audio configuration. Currently rendered only for telephony calls, not - browser WebRTC or direct voice WebSocket sessions. Omit this property to disable all auxiliary - audio. Persisted conversation recordings do not include the soundscape mix. - :vartype soundscape: ~azure.ai.projects.models.VoiceAgentSoundscapeConfig - :ivar output_modalities: The output modalities the agent produces. Defaults to ``["audio"]``. - ``animation`` and ``avatar`` are available when an avatar is configured. - :vartype output_modalities: list[str or ~azure.ai.projects.models.VoiceOutputModality] - :ivar max_output_tokens: The maximum output-token count for one response. Is either a int type - or a Literal["inf"] type. - :vartype max_output_tokens: int or str - :ivar include: Additional fields to include in service outputs. - :vartype include: list[str or ~azure.ai.projects.models.VoiceAgentSessionIncludeOption] - :ivar interim_response: Interim-response settings for latency and tool execution. - :vartype interim_response: ~azure.ai.projects.models.VoiceAgentInterimResponseConfig - :ivar avatar: Optional avatar configuration. These values are session defaults and may be - overridden when connecting. - :vartype avatar: ~azure.ai.projects.models.VoiceAgentAvatarConfig - :ivar tools: The tools the voice agent may use. Supported tool kinds are ``function`` (executed - by the client), ``mcp``, ``system`` (service-managed session controls), and ``toolbox``. - Server-side tools such as ``web_search``, ``azure_ai_search``, and ``openapi`` are provided - through a toolbox rather than declared directly. - :vartype tools: list[~azure.ai.projects.models.VoiceAgentTool] - :ivar tool_choice: How the model chooses tools for generated responses. ``none`` prevents tool - calls, ``auto`` lets the model decide, ``required`` requires at least one tool call, and a - specific function or MCP tool can be selected with an object. Defaults to ``auto``. Is one of - the following types: Literal["none"], Literal["auto"], Literal["required"], ToolChoiceFunction, - ToolChoiceMCP - :vartype tool_choice: str or str or str or ~azure.ai.projects.models.ToolChoiceFunction or - ~azure.ai.projects.models.ToolChoiceMCP - :ivar parallel_tool_calls: Whether the model may call multiple tools in parallel. - :vartype parallel_tool_calls: bool - :ivar structured_inputs: Set of structured inputs that participate in prompt template - substitution, rendered per session before the live session starts. + :ivar structured_inputs: Template inputs for session instructions and supported greetings. :vartype structured_inputs: dict[str, ~azure.ai.projects.models.StructuredInputDefinition] - :ivar subagent_config: Optional configuration for sibling Foundry text agents that this voice - agent may consult as background specialists. - :vartype subagent_config: ~azure.ai.projects.models.VoiceAgentSubagentConfig - :ivar store: Whether conversations with this agent are persisted. A single, all-or-nothing - persistence switch that defaults to ``false`` (privacy-safe: off by default). When ``true``, - Foundry persists the full conversation — the transcript/event timeline and raw audio. When - ``false``, nothing is persisted and no conversation is surfaced. There is no separate - audio-logging control; audio is persisted only as part of this switch. Latency/performance - telemetry (e.g. time-to-first-audio, inter-token latency, interruption) is observability-only - (customer trace / App Insights) and is not part of the persisted conversation content. + :ivar store: Persists conversation content and audio in Foundry, not native Live recordings. + Defaults to false. :vartype store: bool + :ivar sub_protocol: Selects the Live protocol. Required. LIVE. + :vartype sub_protocol: str or ~azure.ai.projects.models.LIVE + :ivar model_type: Uses a Foundry model deployment. Required. The service uses the customer's + own Foundry deployment named by ``model``. + :vartype model_type: str or ~azure.ai.projects.models.SELF_DEPLOYED + :ivar model: The GPT Live deployment name. Required. + :vartype model: str + :ivar greeting: Template-only startup greeting, rendered with session structured inputs. + Foundry-only; not sent in native Live settings. + :vartype greeting: ~azure.ai.projects.models.VoiceAgentTemplateGreetingConfig + :ivar audio: Startup audio formats and output voice. + :vartype audio: ~azure.ai.projects.models.LiveInitialSessionAudioParam + :ivar delegation: Delegation settings. Omit for client mode. responses.model is a backend + deployment name in the Live resource, not a model catalog ID. + :vartype delegation: ~azure.ai.projects.models.VoiceAgentLiveDelegation """ - kind: Literal[AgentKind.VOICE] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The kind discriminator for a voice agent definition. Always ``voice``. Required. VOICE.""" - model_type: Optional[Union[str, "_models.VoiceModelType"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """How the model backing this voice agent is served. Required with ``model`` for a model-backed - voice agent and omitted when ``conversation_engine`` is provided. This is independent of the - architecture (realtime or cascaded), which the service derives from the selected model. Known - values are: \"managed\" and \"self_deployed\".""" - model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The model to use for this agent. Required with ``model_type`` for a model-backed voice agent - and omitted when ``conversation_engine`` is provided. The model must support realtime or - cascaded voice.""" - conversation_engine: Optional["_models.VoiceConversationEngine"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The engine that owns conversation handling for this voice agent. Exactly one of this property - and the model-backed configuration (``model_type`` with ``model``) must be provided. When this - property is provided, ``model_type``, ``model``, ``instructions``, ``tools``, and - ``tool_choice`` must be omitted, and ``greeting.tool_choice`` cannot be ``required``, because - the engine owns the conversation logic. The initial implementation supports a hosted-agent - engine.""" - instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """A system (or developer) message inserted into the model's context. Supports template - substitution via ``structured_inputs``, rendered per session before the live session starts.""" - greeting: Optional["_models.VoiceAgentGreetingConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional session-start greeting. Template mode speaks exact rendered text; LLM-generated mode - asks the session model to author the opening response and may use configured tools.""" - audio: Optional["_models.VoiceAgentAudioConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The audio configuration, including input and output formats, voice, turn detection, noise - reduction, and transcription. These values are session defaults; a client may override - supported fields when connecting.""" - soundscape: Optional["_models.VoiceAgentSoundscapeConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional background ambience and event cues, stored with the agent version and separate from - the audio configuration. Currently rendered only for telephony calls, not browser WebRTC or - direct voice WebSocket sessions. Omit this property to disable all auxiliary audio. Persisted - conversation recordings do not include the soundscape mix.""" - output_modalities: Optional[list[Union[str, "_models.VoiceOutputModality"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The output modalities the agent produces. Defaults to ``[\"audio\"]``. ``animation`` and - ``avatar`` are available when an avatar is configured.""" - max_output_tokens: Optional["_unions.VoiceAgentMaxOutputTokens"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The maximum output-token count for one response. Is either a int type or a Literal[\"inf\"] - type.""" - include: Optional[list[Union[str, "_models.VoiceAgentSessionIncludeOption"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Additional fields to include in service outputs.""" - interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Interim-response settings for latency and tool execution.""" - avatar: Optional["_models.VoiceAgentAvatarConfig"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Optional avatar configuration. These values are session defaults and may be overridden when - connecting.""" - tools: Optional[list["_models.VoiceAgentTool"]] = rest_field( + __mapping__: dict[str, _Model] = {} + sub_protocol: Literal[VoiceAgentSubProtocol.LIVE] = rest_discriminator(name="sub_protocol", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Selects the Live protocol. Required. LIVE.""" + model_type: Literal[VoiceModelType.SELF_DEPLOYED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The tools the voice agent may use. Supported tool kinds are ``function`` (executed by the - client), ``mcp``, ``system`` (service-managed session controls), and ``toolbox``. Server-side - tools such as ``web_search``, ``azure_ai_search``, and ``openapi`` are provided through a - toolbox rather than declared directly.""" - tool_choice: Optional["_unions.VoiceAgentToolChoice"] = rest_field( + """Uses a Foundry model deployment. Required. The service uses the customer's own Foundry + deployment named by ``model``.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The GPT Live deployment name. Required.""" + greeting: Optional["_models.VoiceAgentTemplateGreetingConfig"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """How the model chooses tools for generated responses. ``none`` prevents tool calls, ``auto`` - lets the model decide, ``required`` requires at least one tool call, and a specific function or - MCP tool can be selected with an object. Defaults to ``auto``. Is one of the following types: - Literal[\"none\"], Literal[\"auto\"], Literal[\"required\"], ToolChoiceFunction, ToolChoiceMCP""" - parallel_tool_calls: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the model may call multiple tools in parallel.""" - structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = rest_field( + """Template-only startup greeting, rendered with session structured inputs. Foundry-only; not sent + in native Live settings.""" + audio: Optional["_models.LiveInitialSessionAudioParam"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Set of structured inputs that participate in prompt template substitution, rendered per session - before the live session starts.""" - subagent_config: Optional["_models.VoiceAgentSubagentConfig"] = rest_field( + """Startup audio formats and output voice.""" + delegation: Optional["_models.VoiceAgentLiveDelegation"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Optional configuration for sibling Foundry text agents that this voice agent may consult as - background specialists.""" - store: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether conversations with this agent are persisted. A single, all-or-nothing persistence - switch that defaults to ``false`` (privacy-safe: off by default). When ``true``, Foundry - persists the full conversation — the transcript/event timeline and raw audio. When ``false``, - nothing is persisted and no conversation is surfaced. There is no separate audio-logging - control; audio is persisted only as part of this switch. Latency/performance telemetry (e.g. - time-to-first-audio, inter-token latency, interruption) is observability-only (customer trace / - App Insights) and is not part of the persisted conversation content.""" + """Delegation settings. Omit for client mode. responses.model is a backend deployment name in the + Live resource, not a model catalog ID.""" @overload def __init__( self, *, + model_type: Literal[VoiceModelType.SELF_DEPLOYED], + model: str, rai_config: Optional["_models.RaiConfig"] = None, - model_type: Optional[Union[str, "_models.VoiceModelType"]] = None, - model: Optional[str] = None, - conversation_engine: Optional["_models.VoiceConversationEngine"] = None, instructions: Optional[str] = None, - greeting: Optional["_models.VoiceAgentGreetingConfig"] = None, - audio: Optional["_models.VoiceAgentAudioConfig"] = None, - soundscape: Optional["_models.VoiceAgentSoundscapeConfig"] = None, - output_modalities: Optional[list[Union[str, "_models.VoiceOutputModality"]]] = None, - max_output_tokens: Optional["_unions.VoiceAgentMaxOutputTokens"] = None, - include: Optional[list[Union[str, "_models.VoiceAgentSessionIncludeOption"]]] = None, - interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = None, - avatar: Optional["_models.VoiceAgentAvatarConfig"] = None, - tools: Optional[list["_models.VoiceAgentTool"]] = None, - tool_choice: Optional["_unions.VoiceAgentToolChoice"] = None, - parallel_tool_calls: Optional[bool] = None, structured_inputs: Optional[dict[str, "_models.StructuredInputDefinition"]] = None, - subagent_config: Optional["_models.VoiceAgentSubagentConfig"] = None, store: Optional[bool] = None, + greeting: Optional["_models.VoiceAgentTemplateGreetingConfig"] = None, + audio: Optional["_models.LiveInitialSessionAudioParam"] = None, + delegation: Optional["_models.VoiceAgentLiveDelegation"] = None, ) -> None: ... @overload @@ -28980,42 +38774,49 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.kind = AgentKind.VOICE # type: ignore + self.sub_protocol = VoiceAgentSubProtocol.LIVE # type: ignore -class VoiceAgentEchoCancellation(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Server-side echo cancellation settings for input audio. +class VoiceAgentLiveDelegationItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Live delegation trigger metadata reported to Foundry clients. This object contains metadata, + not the task text. - :ivar type: The echo cancellation implementation. Always ``server_echo_cancellation``. - Required. Default value is "server_echo_cancellation". + :ivar id: The unique ID of the delegation. Use this as delegation_id when replying to + client-owned work or correlating backend events. Required. + :vartype id: str + :ivar type: The object type, always ``delegation``. Required. Default value is "delegation". :vartype type: str - :ivar reference_source: Whether reference audio comes from server playback or a client-provided - channel. Known values are: "server" and "client". - :vartype reference_source: str or - ~azure.ai.projects.models.VoiceAgentEchoCancellationReferenceSource - :ivar channels: The number of input channels. Use two interleaved channels when - ``reference_source`` is ``client``. - :vartype channels: int + :ivar response_id: The ID of the Responses API response associated with a Responses delegation. + Omitted for client delegations. + :vartype response_id: str + :ivar target: Where the work is handled. foundry_managed_agent sessions report + foundry_managed_agent; GPT Live itself uses client. Required. Known values are: "responses", + "client", and "foundry_managed_agent". + :vartype target: str or ~azure.ai.projects.models.VoiceAgentLiveDelegationTarget """ - type: Literal["server_echo_cancellation"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The echo cancellation implementation. Always ``server_echo_cancellation``. Required. Default - value is \"server_echo_cancellation\".""" - reference_source: Optional[Union[str, "_models.VoiceAgentEchoCancellationReferenceSource"]] = rest_field( + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the delegation. Use this as delegation_id when replying to client-owned work + or correlating backend events. Required.""" + type: Literal["delegation"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, always ``delegation``. Required. Default value is \"delegation\".""" + response_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The ID of the Responses API response associated with a Responses delegation. Omitted for client + delegations.""" + target: Union[str, "_models.VoiceAgentLiveDelegationTarget"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Whether reference audio comes from server playback or a client-provided channel. Known values - are: \"server\" and \"client\".""" - channels: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The number of input channels. Use two interleaved channels when ``reference_source`` is - ``client``.""" + """Where the work is handled. foundry_managed_agent sessions report foundry_managed_agent; GPT + Live itself uses client. Required. Known values are: \"responses\", \"client\", and + \"foundry_managed_agent\".""" @overload def __init__( self, *, - reference_source: Optional[Union[str, "_models.VoiceAgentEchoCancellationReferenceSource"]] = None, - channels: Optional[int] = None, + id: str, # pylint: disable=redefined-builtin + target: Union[str, "_models.VoiceAgentLiveDelegationTarget"], + response_id: Optional[str] = None, ) -> None: ... @overload @@ -29027,28 +38828,30 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["server_echo_cancellation"] = "server_echo_cancellation" + self.type: Literal["delegation"] = "delegation" -class VoiceAgentTool(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """A tool usable by a voice agent. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - VoiceAgentFunctionTool, VoiceAgentMcpTool, VoiceAgentSystemTool, VoiceAgentToolboxTool +class VoiceAgentLiveDelegationResultItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Persisted guidance accepted by Live. The service populates commentary, thinking, or both. Agent + delegation section markers are removed before storage. - :ivar type: The tool kind. Required. Default value is None. - :vartype type: str + :ivar commentary: Guidance for Live to communicate to the user. + :vartype commentary: str + :ivar thinking: Background context, not private reasoning or a request to speak. + :vartype thinking: str """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The tool kind. Required. Default value is None.""" + commentary: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Guidance for Live to communicate to the user.""" + thinking: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Background context, not private reasoning or a request to speak.""" @overload def __init__( self, *, - type: str, + commentary: Optional[str] = None, + thinking: Optional[str] = None, ) -> None: ... @overload @@ -29062,39 +38865,84 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentSystemTool( - VoiceAgentTool, discriminator="system" -): # pylint: disable=docstring-keyword-should-match-keyword-only - """A service-managed control that acts on the active voice session without customer code or - external authentication. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - VoiceAgentEndConversationSystemTool +class VoiceAgentLiveFoundryManagedAgentDelegationItem( + VoiceAgentLiveDelegationConversationItem, discriminator="foundry_managed_agent" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Stored prompt-agent delegation state and accepted results. - :ivar type: The type of the tool. Always ``system``. Required. Default value is "system". - :vartype type: str - :ivar name: The service-managed control action. Known values are stable; additional values may - be added over time. Required. "end_conversation" - :vartype name: str or ~azure.ai.projects.models.VoiceAgentSystemToolName - :ivar description: An optional description of the system tool. - :vartype description: str + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str + :ivar response_id: The ID of the Responses API response associated with a Responses delegation. + Omitted for client delegations. + :vartype response_id: str + :ivar type: Required. DELEGATION. + :vartype type: str or ~azure.ai.projects.models.DELEGATION + :ivar created_at: Observed delegation creation time, in Unix seconds. Required. + :vartype created_at: ~datetime.datetime + :ivar target: Required. FOUNDRY_MANAGED_AGENT. + :vartype target: str or ~azure.ai.projects.models.FOUNDRY_MANAGED_AGENT + :ivar agent_name: Target agent name in the same project. Required. + :vartype agent_name: str + :ivar agent_version: Target version pinned at connection start. Required. + :vartype agent_version: str + :ivar offset_ms: Native delegation offset from session start, in milliseconds. Required. + :vartype offset_ms: ~datetime.timedelta + :ivar backend_conversation_id: Backend conversation ID, distinct from the voice conversation + and Live session IDs. + :vartype backend_conversation_id: str + :ivar output: Accepted guidance in order; empty until a result is accepted. Entries have no + individual IDs, are noncumulative, and are independent of backend output_index. Partial results + survive failure or cancellation. Required. + :vartype output: list[~azure.ai.projects.models.VoiceAgentLiveDelegationResultItem] + :ivar delegation_context: Task context sent to the target agent, not the full request body. + :vartype delegation_context: str + :ivar status: The persisted delegation outcome. Required. Known values are: "in_progress", + "completed", "failed", "incomplete", and "cancelled". + :vartype status: str or ~azure.ai.projects.models.VoiceAgentLiveDelegationStatus """ __mapping__: dict[str, _Model] = {} - type: Literal["system"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``system``. Required. Default value is \"system\".""" - name: str = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) - """The service-managed control action. Known values are stable; additional values may be added - over time. Required. \"end_conversation\"""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional description of the system tool.""" + target: Literal[VoiceAgentLiveDelegationTarget.FOUNDRY_MANAGED_AGENT] = rest_discriminator(name="target", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. FOUNDRY_MANAGED_AGENT.""" + agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Target agent name in the same project. Required.""" + agent_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Target version pinned at connection start. Required.""" + offset_ms: datetime.timedelta = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """Native delegation offset from session start, in milliseconds. Required.""" + backend_conversation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Backend conversation ID, distinct from the voice conversation and Live session IDs.""" + output: list["_models.VoiceAgentLiveDelegationResultItem"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Accepted guidance in order; empty until a result is accepted. Entries have no individual IDs, + are noncumulative, and are independent of backend output_index. Partial results survive failure + or cancellation. Required.""" + delegation_context: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Task context sent to the target agent, not the full request body.""" + status: Union[str, "_models.VoiceAgentLiveDelegationStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The persisted delegation outcome. Required. Known values are: \"in_progress\", \"completed\", + \"failed\", \"incomplete\", and \"cancelled\".""" @overload def __init__( self, *, - name: str, - description: Optional[str] = None, + id: str, # pylint: disable=redefined-builtin + created_at: datetime.datetime, + agent_name: str, + agent_version: str, + offset_ms: datetime.timedelta, + output: list["_models.VoiceAgentLiveDelegationResultItem"], + status: Union[str, "_models.VoiceAgentLiveDelegationStatus"], + response_id: Optional[str] = None, + backend_conversation_id: Optional[str] = None, + delegation_context: Optional[str] = None, ) -> None: ... @overload @@ -29106,33 +38954,39 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "system" # type: ignore + self.target = VoiceAgentLiveDelegationTarget.FOUNDRY_MANAGED_AGENT # type: ignore -class VoiceAgentEndConversationSystemTool( - VoiceAgentSystemTool, discriminator="end_conversation" +class VoiceAgentLiveInputConversationItem( + VoiceAgentLiveConversationItem, discriminator="input" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A service-managed control that ends the active conversation. + """A stored user speech segment. - :ivar type: The type of the tool. Always ``system``. Required. Default value is "system". - :vartype type: str - :ivar description: An optional description of the system tool. - :vartype description: str - :ivar name: The service-managed control action. Always ``end_conversation``. Required. Ends the - active conversation. - :vartype name: str or ~azure.ai.projects.models.END_CONVERSATION + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str + :ivar type: Required. INPUT. + :vartype type: str or ~azure.ai.projects.models.INPUT + :ivar transcription: Captured user transcription, when available. + :vartype transcription: str + :ivar audio: Captured audio metadata; audio.item_id matches this item's id. + :vartype audio: ~azure.ai.projects.models.VoiceAudioItem """ - __mapping__: dict[str, _Model] = {} - name: Literal[VoiceAgentSystemToolName.END_CONVERSATION] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The service-managed control action. Always ``end_conversation``. Required. Ends the active - conversation.""" + type: Literal[VoiceAgentLiveConversationItemType.INPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. INPUT.""" + transcription: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Captured user transcription, when available.""" + audio: Optional["_models.VoiceAudioItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Captured audio metadata; audio.item_id matches this item's id.""" @overload def __init__( self, *, - description: Optional[str] = None, + id: str, # pylint: disable=redefined-builtin + transcription: Optional[str] = None, + audio: Optional["_models.VoiceAudioItem"] = None, ) -> None: ... @overload @@ -29144,46 +38998,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.name = VoiceAgentSystemToolName.END_CONVERSATION # type: ignore + self.type = VoiceAgentLiveConversationItemType.INPUT # type: ignore -class VoiceAgentEndOfUtteranceDetection(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Semantic end-of-utterance detection configuration. +class VoiceAgentLiveManagedAgentDelegation( + VoiceAgentLiveDelegation, discriminator="foundry_managed_agent" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Delegates to a same-project prompt agent using native client delegation. Requires [thinking] + and/or [commentary] output sections. - :ivar model: The semantic detection model. Required. Known values are: "semantic_detection_v1", - "semantic_detection_v1_en", "semantic_detection_v1_multilingual", and - "smart_end_of_turn_detection". - :vartype model: str or ~azure.ai.projects.models.VoiceAgentEndOfUtteranceDetectionModel - :ivar threshold_level: The sensitivity threshold. Known values are: "low", "medium", "high", - and "default". - :vartype threshold_level: str or - ~azure.ai.projects.models.VoiceAgentEndOfUtteranceThresholdLevel - :ivar timeout_ms: The detection timeout in milliseconds. - :vartype timeout_ms: ~datetime.timedelta + :ivar type: Canonical delegation type; legacy managed_prompt_agent values are returned as + foundry_managed_agent. Required. A prompt agent in the same project handles delegated work. + :vartype type: str or ~azure.ai.projects.models.FOUNDRY_MANAGED_AGENT + :ivar agent_name: Name of a prompt agent in the same project. Required. + :vartype agent_name: str + :ivar agent_version: Agent version, pinned per connection. Omit to select the active version. + :vartype agent_version: str """ - model: Union[str, "_models.VoiceAgentEndOfUtteranceDetectionModel"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The semantic detection model. Required. Known values are: \"semantic_detection_v1\", - \"semantic_detection_v1_en\", \"semantic_detection_v1_multilingual\", and - \"smart_end_of_turn_detection\".""" - threshold_level: Optional[Union[str, "_models.VoiceAgentEndOfUtteranceThresholdLevel"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The sensitivity threshold. Known values are: \"low\", \"medium\", \"high\", and \"default\".""" - timeout_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" - ) - """The detection timeout in milliseconds.""" + type: Literal[VoiceAgentLiveDelegationType.FOUNDRY_MANAGED_AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Canonical delegation type; legacy managed_prompt_agent values are returned as + foundry_managed_agent. Required. A prompt agent in the same project handles delegated work.""" + agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name of a prompt agent in the same project. Required.""" + agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Agent version, pinned per connection. Omit to select the active version.""" @overload def __init__( self, *, - model: Union[str, "_models.VoiceAgentEndOfUtteranceDetectionModel"], - threshold_level: Optional[Union[str, "_models.VoiceAgentEndOfUtteranceThresholdLevel"]] = None, - timeout_ms: Optional[datetime.timedelta] = None, + agent_name: str, + agent_version: Optional[str] = None, ) -> None: ... @overload @@ -29195,43 +39041,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = VoiceAgentLiveDelegationType.FOUNDRY_MANAGED_AGENT # type: ignore -class VoiceAgentFunctionTool( - VoiceAgentTool, discriminator="function" +class VoiceAgentLiveOutputConversationItem( + VoiceAgentLiveConversationItem, discriminator="output" ): # pylint: disable=docstring-keyword-should-match-keyword-only - """A native function tool executed by the client. + """A stored assistant speech segment. - :ivar description: The description of the function, including guidance on when and how to call - it, and guidance about what to tell the user when calling (if anything). - :vartype description: str - :ivar parameters: Parameters of the function in JSON Schema. - :vartype parameters: ~azure.ai.projects.models.RealtimeFunctionToolParameters - :ivar type: Required. Default value is "function". - :vartype type: str - :ivar name: The function name. Required. - :vartype name: str + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str + :ivar type: Required. OUTPUT. + :vartype type: str or ~azure.ai.projects.models.OUTPUT + :ivar transcription: Captured assistant transcription, not backend output or commentary + guidance. + :vartype transcription: str + :ivar audio: Captured audio metadata; audio.item_id matches this item's id. + :vartype audio: ~azure.ai.projects.models.VoiceAudioItem """ - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The description of the function, including guidance on when and how to call it, and guidance - about what to tell the user when calling (if anything).""" - parameters: Optional["_models.RealtimeFunctionToolParameters"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Parameters of the function in JSON Schema.""" - type: Literal["function"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Default value is \"function\".""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The function name. Required.""" + type: Literal[VoiceAgentLiveConversationItemType.OUTPUT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. OUTPUT.""" + transcription: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Captured assistant transcription, not backend output or commentary guidance.""" + audio: Optional["_models.VoiceAudioItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Captured audio metadata; audio.item_id matches this item's id.""" @overload def __init__( self, *, - name: str, - description: Optional[str] = None, - parameters: Optional["_models.RealtimeFunctionToolParameters"] = None, + id: str, # pylint: disable=redefined-builtin + transcription: Optional[str] = None, + audio: Optional["_models.VoiceAudioItem"] = None, ) -> None: ... @overload @@ -29243,28 +39086,48 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "function" # type: ignore - - -class VoiceAgentGreetingConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Session-start greeting configuration for a voice agent. + self.type = VoiceAgentLiveConversationItemType.OUTPUT # type: ignore - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - VoiceAgentLlmGeneratedGreetingConfig, VoiceAgentTemplateGreetingConfig - - :ivar type: The greeting mode. Required. Default value is None. - :vartype type: str - """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The greeting mode. Required. Default value is None.""" +class VoiceAgentLiveResponsesDelegation( + VoiceAgentLiveDelegation, discriminator="responses" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Delegates work to a Responses backend using native Responses settings. + + :ivar acknowledgement_delay_ms: Milliseconds to wait before requesting an automatic spoken + acknowledgement for a delegation. The model may still speak before this delay. Any commentary + or thinking appended to the session cancels all pending acknowledgements, including those for + other delegations. Defaults to 400 for Decisions sessions and 0 (request immediately) for other + sessions. Omission in a session update preserves the current value. Updates apply to subsequent + delegations. + :vartype acknowledgement_delay_ms: int + :ivar responses: Backend model, prompt, and tools used when the Live session delegates a task + to Responses. Required. + :vartype responses: ~azure.ai.projects.models.LiveResponsesDelegationSettingsInputParam + :ivar type: Required. A Responses backend handles delegated work. + :vartype type: str or ~azure.ai.projects.models.RESPONSES + """ + + acknowledgement_delay_ms: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Milliseconds to wait before requesting an automatic spoken acknowledgement for a delegation. + The model may still speak before this delay. Any commentary or thinking appended to the session + cancels all pending acknowledgements, including those for other delegations. Defaults to 400 + for Decisions sessions and 0 (request immediately) for other sessions. Omission in a session + update preserves the current value. Updates apply to subsequent delegations.""" + responses: "_models.LiveResponsesDelegationSettingsInputParam" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Backend model, prompt, and tools used when the Live session delegates a task to Responses. + Required.""" + type: Literal[VoiceAgentLiveDelegationType.RESPONSES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. A Responses backend handles delegated work.""" @overload def __init__( self, *, - type: str, + responses: "_models.LiveResponsesDelegationSettingsInputParam", + acknowledgement_delay_ms: Optional[int] = None, ) -> None: ... @overload @@ -29276,128 +39139,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = VoiceAgentLiveDelegationType.RESPONSES # type: ignore -class VoiceAgentInputTranscription(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Settings for transcribing input audio, including the transcription model, Custom Speech - deployments, and phrase hints. When ``model`` is ``azure-speech-streaming``, transcription is - supported for cascaded text-model conversations only (not realtime speech-to-speech models), - requires a nonempty ``language`` such as ``en-US`` (comma-separated locales are supported), and - supports ``custom_speech``, ``phrase_list``, and ``profanity_filter``. +class VoiceAgentLiveResponsesDelegationConversationItem( + VoiceAgentLiveDelegationConversationItem, discriminator="responses" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Stored Responses delegation output, separate from Live speech. - :ivar language: The language of the input audio. Supplying the input language in `ISO-639-1 - `_ (e.g. ``en``) format will improve - accuracy and latency. Optional for other transcription models; required and must be nonempty - when ``model`` is ``azure-speech-streaming`` (such as ``en-US``; comma-separated locales are - supported). - :vartype language: str - :ivar languages: Possible languages of the input audio, in `ISO-639-1 - `_ format. Supported by - ``gpt-transcribe`` and ``gpt-live-transcribe``. - :vartype languages: list[str] - :ivar keywords: Words or phrases to guide transcription of the input audio. Supported by - ``gpt-transcribe`` and ``gpt-live-transcribe``. - :vartype keywords: list[str] - :ivar prompt: An optional text to guide the model's style or continue a previous audio segment. - For ``whisper-1``, the `prompt is a list of keywords `_. - For ``gpt-4o-transcribe`` models (excluding ``gpt-4o-transcribe-diarize``), the prompt is a - free text string, for example "expect words related to technology". Prompt is not supported - with ``gpt-realtime-whisper`` in GA Realtime sessions. - :vartype prompt: str - :ivar delay: Controls how long the model waits before emitting transcription text. Higher - values can improve transcription accuracy at the cost of latency. Only supported with - ``gpt-realtime-whisper`` in GA Realtime sessions. Is one of the following types: - Literal["minimal"], Literal["low"], Literal["medium"], Literal["high"], Literal["xhigh"] - :vartype delay: str or str or str or str or str - :ivar model: The transcription model identifier. Configure customer custom speech deployments - in ``custom_speech``. ``azure-speech-streaming`` is for cascaded text-model conversations only - (not realtime speech-to-speech models), requires a nonempty ``language`` such as ``en-US`` - (comma-separated locales are supported), and supports ``custom_speech``, ``phrase_list``, and - ``profanity_filter``. Required. Known values are: "whisper-1", "gpt-realtime-whisper", - "gpt-4o-transcribe", "gpt-4o-mini-transcribe", "gpt-4o-transcribe-diarize", "gpt-transcribe", - "gpt-live-transcribe", "mai-transcribe", "azure-speech", and "azure-speech-streaming". - :vartype model: str or ~azure.ai.projects.models.VoiceAgentInputTranscriptionModel - :ivar custom_speech: Optional customer custom speech deployment configuration, keyed by locale. - :vartype custom_speech: dict[str, str] - :ivar phrase_list: Optional phrase hints that bias recognition toward domain terms. - :vartype phrase_list: list[str] - :ivar profanity_filter: Controls how profanity is handled in input transcripts. Supported only - with managed Azure Speech (``azure-speech`` and ``azure-speech-streaming``), including Custom - Speech. Set this property before the session starts. If omitted, the transcription provider's - default applies. You cannot change the mode during a session. Filtering affects transcript - events and the text sent to cascaded models. It does not change input audio, voice activity - detection, or assistant speech; audio-native models still receive the original audio. Mandatory - service masking policies apply even when you select ``unfiltered``. Known values are: "masked", - "unfiltered", and "removed". - :vartype profanity_filter: str or ~azure.ai.projects.models.VoiceAgentProfanityFilterMode + :ivar id: Item ID used for retrieval. Foundry assigns speech IDs; delegation IDs retain their + native value. Required. + :vartype id: str + :ivar response_id: The ID of the Responses API response associated with a Responses delegation. + Omitted for client delegations. + :vartype response_id: str + :ivar type: Required. DELEGATION. + :vartype type: str or ~azure.ai.projects.models.DELEGATION + :ivar created_at: Observed delegation creation time, in Unix seconds. Required. + :vartype created_at: ~datetime.datetime + :ivar target: Required. RESPONSES. + :vartype target: str or ~azure.ai.projects.models.RESPONSES + :ivar output: Final backend text, omitted when unavailable; excludes raw tool output. + :vartype output: str """ - language: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The language of the input audio. Supplying the input language in `ISO-639-1 - `_ (e.g. ``en``) format will improve - accuracy and latency. Optional for other transcription models; required and must be nonempty - when ``model`` is ``azure-speech-streaming`` (such as ``en-US``; comma-separated locales are - supported).""" - languages: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Possible languages of the input audio, in `ISO-639-1 - `_ format. Supported by - ``gpt-transcribe`` and ``gpt-live-transcribe``.""" - keywords: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Words or phrases to guide transcription of the input audio. Supported by ``gpt-transcribe`` and - ``gpt-live-transcribe``.""" - prompt: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """An optional text to guide the model's style or continue a previous audio segment. For - ``whisper-1``, the `prompt is a list of keywords `_. For - ``gpt-4o-transcribe`` models (excluding ``gpt-4o-transcribe-diarize``), the prompt is a free - text string, for example \"expect words related to technology\". Prompt is not supported with - ``gpt-realtime-whisper`` in GA Realtime sessions.""" - delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Controls how long the model waits before emitting transcription text. Higher values can improve - transcription accuracy at the cost of latency. Only supported with ``gpt-realtime-whisper`` in - GA Realtime sessions. Is one of the following types: Literal[\"minimal\"], Literal[\"low\"], - Literal[\"medium\"], Literal[\"high\"], Literal[\"xhigh\"]""" - model: Union[str, "_models.VoiceAgentInputTranscriptionModel"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The transcription model identifier. Configure customer custom speech deployments in - ``custom_speech``. ``azure-speech-streaming`` is for cascaded text-model conversations only - (not realtime speech-to-speech models), requires a nonempty ``language`` such as ``en-US`` - (comma-separated locales are supported), and supports ``custom_speech``, ``phrase_list``, and - ``profanity_filter``. Required. Known values are: \"whisper-1\", \"gpt-realtime-whisper\", - \"gpt-4o-transcribe\", \"gpt-4o-mini-transcribe\", \"gpt-4o-transcribe-diarize\", - \"gpt-transcribe\", \"gpt-live-transcribe\", \"mai-transcribe\", \"azure-speech\", and - \"azure-speech-streaming\".""" - custom_speech: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional customer custom speech deployment configuration, keyed by locale.""" - phrase_list: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional phrase hints that bias recognition toward domain terms.""" - profanity_filter: Optional[Union[str, "_models.VoiceAgentProfanityFilterMode"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Controls how profanity is handled in input transcripts. Supported only with managed Azure - Speech (``azure-speech`` and ``azure-speech-streaming``), including Custom Speech. Set this - property before the session starts. If omitted, the transcription provider's default applies. - You cannot change the mode during a session. Filtering affects transcript events and the text - sent to cascaded models. It does not change input audio, voice activity detection, or assistant - speech; audio-native models still receive the original audio. Mandatory service masking - policies apply even when you select ``unfiltered``. Known values are: \"masked\", - \"unfiltered\", and \"removed\".""" + __mapping__: dict[str, _Model] = {} + target: Literal[VoiceAgentLiveDelegationTarget.RESPONSES] = rest_discriminator(name="target", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. RESPONSES.""" + output: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Final backend text, omitted when unavailable; excludes raw tool output.""" @overload def __init__( self, *, - model: Union[str, "_models.VoiceAgentInputTranscriptionModel"], - language: Optional[str] = None, - languages: Optional[list[str]] = None, - keywords: Optional[list[str]] = None, - prompt: Optional[str] = None, - delay: Optional[Literal["minimal", "low", "medium", "high", "xhigh"]] = None, - custom_speech: Optional[dict[str, str]] = None, - phrase_list: Optional[list[str]] = None, - profanity_filter: Optional[Union[str, "_models.VoiceAgentProfanityFilterMode"]] = None, + id: str, # pylint: disable=redefined-builtin + created_at: datetime.datetime, + response_id: Optional[str] = None, + output: Optional[str] = None, ) -> None: ... @overload @@ -29409,41 +39188,105 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.target = VoiceAgentLiveDelegationTarget.RESPONSES # type: ignore -class VoiceAgentInterimResponseConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Fields shared by interim-response configurations. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - VoiceAgentLlmInterimResponseConfig, VoiceAgentStaticInterimResponseConfig +class VoiceAgentLiveSessionResource(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Live session resource reported to Foundry clients. GPT Live runs native client delegation for + foundry_managed_agent sessions; Foundry reports the effective owner. - :ivar type: The interim-response implementation. Required. Default value is None. - :vartype type: str - :ivar triggers: Conditions that may trigger one interim response. - :vartype triggers: list[str or ~azure.ai.projects.models.VoiceAgentInterimResponseTrigger] - :ivar latency_threshold_ms: The latency threshold in milliseconds. - :vartype latency_threshold_ms: ~datetime.timedelta + :ivar model: Required. "gpt-live-1" + :vartype model: str or ~azure.ai.projects.models.ModelIdsLive + :ivar instructions: + :vartype instructions: str + :ivar input: Ordered text-only history supplied before startup. Supports developer, user, and + assistant messages with one text part each; at most 128 messages and a configured + rendered-token limit (8,192 by default). + :vartype input: list[~azure.ai.projects.models.LiveInitialItem] + :ivar audio: Startup audio configuration. Only primary WebSockets accept audio.format; WebRTC + and SIP negotiate their media format. Voice and format are immutable after startup. + :vartype audio: ~azure.ai.projects.models.LiveInitialSessionAudioParam + :ivar triggers: At most one Decisions trigger per transcript event type. Triggers run + independently of delegation. On update, omit triggers to keep the current configuration, send a + list to replace it, or send an empty list to disable triggers. + :vartype triggers: list[~azure.ai.projects.models.LiveDecisionTriggerInputParam] + :ivar store: Whether to store the session for later forking and recording download. Defaults to + false for new sessions. + :vartype store: bool + :ivar client: Startup-only capabilities for an untrusted frontend attached to a unified WebRTC + session. Trusted sideband connections are unaffected. + :vartype client: ~azure.ai.projects.models.LiveClientConfigParam + :ivar id: The unique ID of the Live session. Use this ID for sideband connections, forking, and + recording download. Required. + :vartype id: str + :ivar expires_at: The Unix timestamp, in seconds, at which the Live session expires. Required. + :vartype expires_at: int + :ivar status: The status of the session snapshot. Always ``active``, including the final + snapshot in session.closed; use the event type to determine that the session has closed. + Required. Default value is "active". + :vartype status: str + :ivar delegation: Delegation owner. foundry_managed_agent sessions report the pinned target, + including the resolved agent_version. + :vartype delegation: ~azure.ai.projects.models.VoiceAgentLiveDelegation """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The interim-response implementation. Required. Default value is None.""" - triggers: Optional[list[Union[str, "_models.VoiceAgentInterimResponseTrigger"]]] = rest_field( + model: Union[str, "_models.ModelIdsLive"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. \"gpt-live-1\"""" + instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + input: Optional[list["_models.LiveInitialItem"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Conditions that may trigger one interim response.""" - latency_threshold_ms: Optional[datetime.timedelta] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + """Ordered text-only history supplied before startup. Supports developer, user, and assistant + messages with one text part each; at most 128 messages and a configured rendered-token limit + (8,192 by default).""" + audio: Optional["_models.LiveInitialSessionAudioParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """The latency threshold in milliseconds.""" + """Startup audio configuration. Only primary WebSockets accept audio.format; WebRTC and SIP + negotiate their media format. Voice and format are immutable after startup.""" + triggers: Optional[list["_models.LiveDecisionTriggerInputParam"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """At most one Decisions trigger per transcript event type. Triggers run independently of + delegation. On update, omit triggers to keep the current configuration, send a list to replace + it, or send an empty list to disable triggers.""" + store: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether to store the session for later forking and recording download. Defaults to false for + new sessions.""" + client: Optional["_models.LiveClientConfigParam"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Startup-only capabilities for an untrusted frontend attached to a unified WebRTC session. + Trusted sideband connections are unaffected.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the Live session. Use this ID for sideband connections, forking, and recording + download. Required.""" + expires_at: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The Unix timestamp, in seconds, at which the Live session expires. Required.""" + status: Literal["active"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The status of the session snapshot. Always ``active``, including the final snapshot in + session.closed; use the event type to determine that the session has closed. Required. Default + value is \"active\".""" + delegation: Optional["_models.VoiceAgentLiveDelegation"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Delegation owner. foundry_managed_agent sessions report the pinned target, including the + resolved agent_version.""" @overload def __init__( self, *, - type: str, - triggers: Optional[list[Union[str, "_models.VoiceAgentInterimResponseTrigger"]]] = None, - latency_threshold_ms: Optional[datetime.timedelta] = None, + model: Union[str, "_models.ModelIdsLive"], + id: str, # pylint: disable=redefined-builtin + expires_at: int, + instructions: Optional[str] = None, + input: Optional[list["_models.LiveInitialItem"]] = None, + audio: Optional["_models.LiveInitialSessionAudioParam"] = None, + triggers: Optional[list["_models.LiveDecisionTriggerInputParam"]] = None, + store: Optional[bool] = None, + client: Optional["_models.LiveClientConfigParam"] = None, + delegation: Optional["_models.VoiceAgentLiveDelegation"] = None, ) -> None: ... @overload @@ -29455,6 +39298,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.status: Literal["active"] = "active" class VoiceAgentLlmGeneratedGreetingConfig( @@ -29462,8 +39306,8 @@ class VoiceAgentLlmGeneratedGreetingConfig( ): # pylint: disable=docstring-keyword-should-match-keyword-only """A greeting authored by the session model from a scoped opening-turn prompt. - :ivar type: Required. Default value is "llm_generated". - :vartype type: str + :ivar type: Required. Generate the greeting with the session model from an opening-turn prompt. + :vartype type: str or ~azure.ai.projects.models.LLM_GENERATED :ivar prompt: The Handlebars prompt that guides the opening turn. Required. :vartype prompt: str :ivar tool_choice: The tool-selection policy for the opening response. Defaults to ``none``. Is @@ -29473,8 +39317,8 @@ class VoiceAgentLlmGeneratedGreetingConfig( ~azure.ai.projects.models.ToolChoiceMCP """ - type: Literal["llm_generated"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Default value is \"llm_generated\".""" + type: Literal[VoiceAgentGreetingMode.LLM_GENERATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Generate the greeting with the session model from an opening-turn prompt.""" prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The Handlebars prompt that guides the opening turn. Required.""" tool_choice: Optional["_unions.VoiceAgentToolChoice"] = rest_field( @@ -29501,7 +39345,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "llm_generated" # type: ignore + self.type = VoiceAgentGreetingMode.LLM_GENERATED # type: ignore class VoiceAgentLlmInterimResponseConfig( @@ -29513,8 +39357,8 @@ class VoiceAgentLlmInterimResponseConfig( :vartype triggers: list[str or ~azure.ai.projects.models.VoiceAgentInterimResponseTrigger] :ivar latency_threshold_ms: The latency threshold in milliseconds. :vartype latency_threshold_ms: ~datetime.timedelta - :ivar type: Required. Default value is "llm_interim_response". - :vartype type: str + :ivar type: Required. Generate an interim response with a language model. + :vartype type: str or ~azure.ai.projects.models.LLM_INTERIM_RESPONSE :ivar model: The model used to generate interim responses. :vartype model: str :ivar instructions: Optional instructions for generating interim responses. @@ -29523,8 +39367,8 @@ class VoiceAgentLlmInterimResponseConfig( :vartype max_completion_tokens: int """ - type: Literal["llm_interim_response"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Default value is \"llm_interim_response\".""" + type: Literal[VoiceAgentInterimResponseType.LLM_INTERIM_RESPONSE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Generate an interim response with a language model.""" model: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The model used to generate interim responses.""" instructions: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -29552,7 +39396,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "llm_interim_response" # type: ignore + self.type = VoiceAgentInterimResponseType.LLM_INTERIM_RESPONSE # type: ignore class VoiceAgentMcpTool( @@ -29590,8 +39434,8 @@ class VoiceAgentMcpTool( :ivar tool_configs: Deprecated. This property is deprecated and will be removed in a future version. :vartype tool_configs: dict[str, ~azure.ai.projects.models.ToolConfig] - :ivar type: Required. Default value is "mcp". - :vartype type: str + :ivar type: Required. A tool exposed by an MCP server. + :vartype type: str or ~azure.ai.projects.models.MCP :ivar response_scheduling: When the MCP invocation creates a follow-up response. Defaults to ``when_idle``. Known values are: "silent", "when_idle", "interrupt", and "skip_if_busy". :vartype response_scheduling: str or ~azure.ai.projects.models.VoiceAgentToolResponseScheduling @@ -29629,8 +39473,8 @@ class VoiceAgentMcpTool( visibility=["read", "create", "update", "delete", "query"] ) """Deprecated. This property is deprecated and will be removed in a future version.""" - type: Literal["mcp"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Default value is \"mcp\".""" + type: Literal[VoiceAgentToolType.MCP] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. A tool exposed by an MCP server.""" response_scheduling: Optional[Union[str, "_models.VoiceAgentToolResponseScheduling"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -29664,7 +39508,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "mcp" # type: ignore + self.type = VoiceAgentToolType.MCP # type: ignore class VoiceAgentNoiseReduction(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -29715,6 +39559,46 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class VoiceAgentPostCallConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """Post-call delivery configuration. + + :ivar destinations: The destinations to notify. Required. + :vartype destinations: list[~azure.ai.projects.models.VoiceAgentPostCallDestination] + :ivar include: Additional content to include in each delivery. The transcript is always + delivered. ``audio`` is not supported in this preview; the service rejects it when the agent + version is saved. + :vartype include: list[str or ~azure.ai.projects.models.VoiceAgentPostCallIncludeOption] + """ + + destinations: list["_models.VoiceAgentPostCallDestination"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The destinations to notify. Required.""" + include: Optional[list[Union[str, "_models.VoiceAgentPostCallIncludeOption"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Additional content to include in each delivery. The transcript is always delivered. ``audio`` + is not supported in this preview; the service rejects it when the agent version is saved.""" + + @overload + def __init__( + self, + *, + destinations: list["_models.VoiceAgentPostCallDestination"], + include: Optional[list[Union[str, "_models.VoiceAgentPostCallIncludeOption"]]] = 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 VoiceAgentRealtimeResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """A live realtime response returned by the voice-agent service in both ``response.created`` and ``response.done`` events. @@ -29879,7 +39763,10 @@ class VoiceAgentResponseCreateParams(_Model): # pylint: disable=docstring-keywo context for this Response instead of using the default conversation. An empty array ``[]`` will clear the context for this Response. Note that this can include references to items that previously appeared in the session using their id. - :vartype input: list[~azure.ai.projects.models.RealtimeConversationItem] + :vartype input: list[~azure.ai.projects.models.RealtimeResponseInputMessage or + ~azure.ai.projects.models.RealtimeResponseInputFunctionCall or + ~azure.ai.projects.models.RealtimeResponseInputFunctionCallOutput or + ~azure.ai.projects.models.RealtimeResponseItemReference] :ivar output_modalities: Modalities that the response may return. :vartype output_modalities: list[str or ~azure.ai.projects.models.VoiceOutputModality] :ivar audio: Response-specific audio settings. @@ -29932,7 +39819,7 @@ class VoiceAgentResponseCreateParams(_Model): # pylint: disable=docstring-keywo response which will not add items to default conversation. Is one of the following types: Literal[\"auto\"], Literal[\"none\"], str""" metadata: Optional["_models.Metadata"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - input: Optional[list["_models.RealtimeConversationItem"]] = rest_field( + input: Optional[list["_unions.RealtimeResponseInputItem"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) """Input items to include in the prompt for the model. Using this field creates a new context for @@ -29970,7 +39857,7 @@ def __init__( max_output_tokens: Optional[Union[int, Literal["inf"]]] = None, conversation: Optional[Union[Literal["auto"], Literal["none"], str]] = None, metadata: Optional["_models.Metadata"] = None, - input: Optional[list["_models.RealtimeConversationItem"]] = None, + input: Optional[list["_unions.RealtimeResponseInputItem"]] = None, output_modalities: Optional[list[Union[str, "_models.VoiceOutputModality"]]] = None, audio: Optional["_models.PickPropertiesVoiceAgentAudioConfig"] = None, pre_generated_assistant_message: Optional["_models.RealtimeConversationItem"] = None, @@ -29988,24 +39875,62 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class VoiceAgentRoutinePostCallDestination( + VoiceAgentPostCallDestination, discriminator="routine" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """A routine that is dispatched with the post-call event. + + :ivar type: The destination type. Always ``routine``. Required. A routine. + :vartype type: str or ~azure.ai.projects.models.ROUTINE + :ivar name: The name of the routine. Required. + :vartype name: str + """ + + type: Literal[VoiceAgentPostCallDestinationType.ROUTINE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The destination type. Always ``routine``. Required. A routine.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the routine. Required.""" + + @overload + def __init__( + self, + *, + 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) + self.type = VoiceAgentPostCallDestinationType.ROUTINE # type: ignore + + class VoiceAgentRtcCallErrorDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Details of a WebRTC signaling error. :ivar type: The error category, following the VoiceLive wire contract: ``invalid_request_error`` for a client-side signaling fault (for example, a malformed SDP offer) or ``server_error`` for a service-side failure. Additional categories may be added over - time. Required. - :vartype type: str + time. Required. Known values are: "invalid_request_error" and "server_error". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentRtcCallErrorType :ivar code: A machine-readable error code, when available. :vartype code: str :ivar message: A human-readable error message. Required. :vartype message: str """ - type: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + type: Union[str, "_models.VoiceAgentRtcCallErrorType"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) """The error category, following the VoiceLive wire contract: ``invalid_request_error`` for a client-side signaling fault (for example, a malformed SDP offer) or ``server_error`` for a - service-side failure. Additional categories may be added over time. Required.""" + service-side failure. Additional categories may be added over time. Required. Known values are: + \"invalid_request_error\" and \"server_error\".""" code: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A machine-readable error code, when available.""" message: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -30015,7 +39940,7 @@ class VoiceAgentRtcCallErrorDetails(_Model): # pylint: disable=docstring-keywor def __init__( self, *, - type: str, + type: Union[str, "_models.VoiceAgentRtcCallErrorType"], message: str, code: Optional[str] = None, ) -> None: ... @@ -30082,6 +40007,184 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = VoiceAgentTurnDetectionType.SEMANTIC_VAD # type: ignore +class VoiceAgentSendDtmfSystemTool( + VoiceAgentSystemTool, discriminator="send_dtmf" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Sends literal or templated keypad digits. + + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``send_dtmf``. Required. Sends literal + or templated keypad digits. + :vartype name: str or ~azure.ai.projects.models.SEND_DTMF + """ + + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.SEND_DTMF] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``send_dtmf``. Required. Sends literal or templated + keypad digits.""" + + @overload + def __init__( + self, + *, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = 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.name = VoiceAgentSystemToolName.SEND_DTMF # type: ignore + + +class VoiceAgentSendSmsSystemTool( + VoiceAgentSystemTool, discriminator="send_sms" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Sends a text message from the Agent's SMS-capable number. + + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``send_sms``. Required. Sends a text + message from the Agent's SMS-capable number. + :vartype name: str or ~azure.ai.projects.models.SEND_SMS + """ + + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.SEND_SMS] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``send_sms``. Required. Sends a text message from + the Agent's SMS-capable number.""" + + @overload + def __init__( + self, + *, + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = 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.name = VoiceAgentSystemToolName.SEND_SMS # type: ignore + + +class VoiceAgentServerEventInputCollectionStatus( + RealtimeServerEvent, discriminator="input_collection.status" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """Reports collection or telephony outcomes for a model call. + + :ivar type: The event type. Always ``input_collection.status``. Required. An asynchronous + collection or telephony-operation outcome. + :vartype type: str or ~azure.ai.projects.models.INPUT_COLLECTION_STATUS + :ivar event_id: An optional event identifier. + :vartype event_id: str + :ivar call_id: The originating system-tool invocation. Required. + :vartype call_id: str + :ivar collection_id: The collection operation identifier, when this outcome concerns a + collection. + :vartype collection_id: str + :ivar request_id: The current receiver request identifier, when applicable. + :vartype request_id: str + :ivar channel: The collection receiver, omitted for telephony-operation feedback. Known values + are: "sms" and "dtmf". + :vartype channel: str or ~azure.ai.projects.models.VoiceAgentInputCollectionChannel + :ivar status: The reported outcome. Generation completion of a system-tool item is separate. + Required. Known values are: "accepted", "listening", "completed", "expired", "cancelled", + "failed", "busy", "invalid_input", "invalid_arguments", "stale_collection", + "unsupported_channel", "dispatch_failed", "provider_accepted", "transfer_not_answered", + "provider_failed_or_unsupported", "provider_result_uncertain", and "provider_not_executed". + :vartype status: str or ~azure.ai.projects.models.VoiceAgentInputCollectionStatus + :ivar value: Completed ASCII digits, including leading zeros, only for ``secret: false``; + absent for private collection and telephony-operation feedback. + :vartype value: str + :ivar output_ref: Actual bare variable name from successful private collection, not its value. + May be suffixed on collision; reference it with ``{{name}}``. + :vartype output_ref: str + """ + + type: Literal[VoiceAgentServerEventTypeExtension.INPUT_COLLECTION_STATUS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``input_collection.status``. Required. An asynchronous collection or + telephony-operation outcome.""" + event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An optional event identifier.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The originating system-tool invocation. Required.""" + collection_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The collection operation identifier, when this outcome concerns a collection.""" + request_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The current receiver request identifier, when applicable.""" + channel: Optional[Union[str, "_models.VoiceAgentInputCollectionChannel"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The collection receiver, omitted for telephony-operation feedback. Known values are: \"sms\" + and \"dtmf\".""" + status: Union[str, "_models.VoiceAgentInputCollectionStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The reported outcome. Generation completion of a system-tool item is separate. Required. Known + values are: \"accepted\", \"listening\", \"completed\", \"expired\", \"cancelled\", \"failed\", + \"busy\", \"invalid_input\", \"invalid_arguments\", \"stale_collection\", + \"unsupported_channel\", \"dispatch_failed\", \"provider_accepted\", \"transfer_not_answered\", + \"provider_failed_or_unsupported\", \"provider_result_uncertain\", and + \"provider_not_executed\".""" + value: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Completed ASCII digits, including leading zeros, only for ``secret: false``; absent for private + collection and telephony-operation feedback.""" + output_ref: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Actual bare variable name from successful private collection, not its value. May be suffixed on + collision; reference it with ``{{name}}``.""" + + @overload + def __init__( + self, + *, + call_id: str, + status: Union[str, "_models.VoiceAgentInputCollectionStatus"], + event_id: Optional[str] = None, + collection_id: Optional[str] = None, + request_id: Optional[str] = None, + channel: Optional[Union[str, "_models.VoiceAgentInputCollectionChannel"]] = None, + value: Optional[str] = None, + output_ref: 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 = VoiceAgentServerEventTypeExtension.INPUT_COLLECTION_STATUS # type: ignore + + class VoiceAgentServerEventResponseAnimationBlendshapesDelta( RealtimeServerEvent, discriminator="response.animation_blendshapes.delta" ): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only @@ -30105,7 +40208,7 @@ class VoiceAgentServerEventResponseAnimationBlendshapesDelta( :vartype frame_index: int """ - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_BLENDSHAPES_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_BLENDSHAPES_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_ANIMATION_BLENDSHAPES_DELTA.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30144,7 +40247,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_ANIMATION_BLENDSHAPES_DELTA # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_BLENDSHAPES_DELTA # type: ignore class VoiceAgentServerEventResponseAnimationBlendshapesDone( @@ -30164,7 +40267,7 @@ class VoiceAgentServerEventResponseAnimationBlendshapesDone( :vartype output_index: int """ - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_BLENDSHAPES_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_BLENDSHAPES_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_ANIMATION_BLENDSHAPES_DONE.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30194,7 +40297,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_ANIMATION_BLENDSHAPES_DONE # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_BLENDSHAPES_DONE # type: ignore class VoiceAgentServerEventResponseAnimationVisemeDelta( @@ -30220,7 +40323,7 @@ class VoiceAgentServerEventResponseAnimationVisemeDelta( :vartype viseme_id: int """ - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_VISEME_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_VISEME_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_ANIMATION_VISEME_DELTA.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30261,7 +40364,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_ANIMATION_VISEME_DELTA # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_VISEME_DELTA # type: ignore class VoiceAgentServerEventResponseAnimationVisemeDone( @@ -30283,7 +40386,7 @@ class VoiceAgentServerEventResponseAnimationVisemeDone( :vartype content_index: int """ - type: Literal[RealtimeServerEventType.RESPONSE_ANIMATION_VISEME_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_VISEME_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_ANIMATION_VISEME_DONE.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30316,7 +40419,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_ANIMATION_VISEME_DONE # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_ANIMATION_VISEME_DONE # type: ignore class VoiceAgentServerEventResponseAudioTimestampDelta( @@ -30342,11 +40445,11 @@ class VoiceAgentServerEventResponseAudioTimestampDelta( :vartype audio_duration_ms: ~datetime.timedelta :ivar text: Required. :vartype text: str - :ivar timestamp_type: Required. Default value is "word". - :vartype timestamp_type: str + :ivar timestamp_type: Required. Word-level timestamps. + :vartype timestamp_type: str or ~azure.ai.projects.models.WORD """ - type: Literal[RealtimeServerEventType.RESPONSE_AUDIO_TIMESTAMP_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_AUDIO_TIMESTAMP_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_AUDIO_TIMESTAMP_DELTA.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30368,8 +40471,10 @@ class VoiceAgentServerEventResponseAudioTimestampDelta( """Required.""" text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" - timestamp_type: Literal["word"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required. Default value is \"word\".""" + timestamp_type: Literal[VoiceAgentAudioTimestampType.WORD] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required. Word-level timestamps.""" @overload def __init__( @@ -30383,6 +40488,7 @@ def __init__( audio_offset_ms: datetime.timedelta, audio_duration_ms: datetime.timedelta, text: str, + timestamp_type: Literal[VoiceAgentAudioTimestampType.WORD], ) -> None: ... @overload @@ -30394,8 +40500,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_AUDIO_TIMESTAMP_DELTA # type: ignore - self.timestamp_type: Literal["word"] = "word" + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_AUDIO_TIMESTAMP_DELTA # type: ignore class VoiceAgentServerEventResponseAudioTimestampDone( @@ -30417,7 +40522,7 @@ class VoiceAgentServerEventResponseAudioTimestampDone( :vartype content_index: int """ - type: Literal[RealtimeServerEventType.RESPONSE_AUDIO_TIMESTAMP_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_AUDIO_TIMESTAMP_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_AUDIO_TIMESTAMP_DONE.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30450,7 +40555,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_AUDIO_TIMESTAMP_DONE # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_AUDIO_TIMESTAMP_DONE # type: ignore class VoiceAgentServerEventResponseVideoDelta( @@ -30470,7 +40575,7 @@ class VoiceAgentServerEventResponseVideoDelta( :vartype delta: str """ - type: Literal[RealtimeServerEventType.RESPONSE_VIDEO_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_VIDEO_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. RESPONSE_VIDEO_DELTA.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30500,7 +40605,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RESPONSE_VIDEO_DELTA # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RESPONSE_VIDEO_DELTA # type: ignore class VoiceAgentServerEventRtcCallError( @@ -30520,7 +40625,7 @@ class VoiceAgentServerEventRtcCallError( :vartype error: ~azure.ai.projects.models.VoiceAgentRtcCallErrorDetails """ - type: Literal[RealtimeServerEventType.RTC_CALL_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RTC_CALL_ERROR] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The event type. Always ``rtc.call.error``. Required. RTC_CALL_ERROR.""" event_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """An optional server-generated event identifier.""" @@ -30552,7 +40657,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RTC_CALL_ERROR # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RTC_CALL_ERROR # type: ignore class VoiceAgentServerEventRtcCallSdpCreated( @@ -30570,7 +40675,7 @@ class VoiceAgentServerEventRtcCallSdpCreated( :vartype sdp_answer: str """ - type: Literal[RealtimeServerEventType.RTC_CALL_SDP_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.RTC_CALL_SDP_CREATED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The event type. Always ``rtc.call.sdp.created``. Required. RTC_CALL_SDP_CREATED.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The server-generated event identifier. Required.""" @@ -30597,7 +40702,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.RTC_CALL_SDP_CREATED # type: ignore + self.type = VoiceAgentServerEventTypeExtension.RTC_CALL_SDP_CREATED # type: ignore class VoiceAgentServerEventSessionAvatarConnecting( @@ -30613,7 +40718,7 @@ class VoiceAgentServerEventSessionAvatarConnecting( :vartype server_sdp: str """ - type: Literal[RealtimeServerEventType.SESSION_AVATAR_CONNECTING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_AVATAR_CONNECTING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. SESSION_AVATAR_CONNECTING.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30637,7 +40742,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_AVATAR_CONNECTING # type: ignore + self.type = VoiceAgentServerEventTypeExtension.SESSION_AVATAR_CONNECTING # type: ignore class VoiceAgentServerEventSessionAvatarSwitchToIdle( @@ -30653,7 +40758,7 @@ class VoiceAgentServerEventSessionAvatarSwitchToIdle( :vartype turn_id: str """ - type: Literal[RealtimeServerEventType.SESSION_AVATAR_SWITCH_TO_IDLE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_AVATAR_SWITCH_TO_IDLE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. SESSION_AVATAR_SWITCH_TO_IDLE.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30676,7 +40781,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_AVATAR_SWITCH_TO_IDLE # type: ignore + self.type = VoiceAgentServerEventTypeExtension.SESSION_AVATAR_SWITCH_TO_IDLE # type: ignore class VoiceAgentServerEventSessionAvatarSwitchToSpeaking( @@ -30692,7 +40797,7 @@ class VoiceAgentServerEventSessionAvatarSwitchToSpeaking( :vartype turn_id: str """ - type: Literal[RealtimeServerEventType.SESSION_AVATAR_SWITCH_TO_SPEAKING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_AVATAR_SWITCH_TO_SPEAKING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. SESSION_AVATAR_SWITCH_TO_SPEAKING.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30715,7 +40820,271 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_AVATAR_SWITCH_TO_SPEAKING # type: ignore + self.type = VoiceAgentServerEventTypeExtension.SESSION_AVATAR_SWITCH_TO_SPEAKING # type: ignore + + +class VoiceAgentServerEventSessionHandoffAborted( + RealtimeServerEvent, discriminator="session.handoff.aborted" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The ``session.handoff.aborted`` server event. + + :ivar event_id: The server-generated event identifier. Required. + :vartype event_id: str + :ivar handoff_id: The server-generated handoff attempt identifier. Required. + :vartype handoff_id: str + :ivar edge_id: The configured edge selected for this handoff. Required. + :vartype edge_id: str + :ivar from_node_id: The source node identifier or ``$entrypoint``. Required. + :vartype from_node_id: str + :ivar to_node_id: The target node identifier or ``$entrypoint``. Required. + :vartype to_node_id: str + :ivar from_model: The model active before the handoff. Required. + :vartype from_model: str + :ivar to_model: The model prepared for the target behavior. Required. + :vartype to_model: str + :ivar tool_call_id: The function-call identifier that initiated the handoff. Required. + :vartype tool_call_id: str + :ivar node_generation: The source generation for started or aborted events, and the committed + target generation for completed events. Required. + :vartype node_generation: int + :ivar reason: Why the handoff ended before target commit. Required. Known values are: + "user_interruption" and "error". + :vartype reason: str or ~azure.ai.projects.models.VoiceAgentHandoffAbortReason + :ivar error: The handoff failure detail when ``reason`` is ``error``. + :vartype error: ~azure.ai.projects.models.RealtimeServerEventErrorError + :ivar type: The event type. Always ``session.handoff.aborted``. Required. + SESSION_HANDOFF_ABORTED. + :vartype type: str or ~azure.ai.projects.models.SESSION_HANDOFF_ABORTED + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The server-generated event identifier. Required.""" + handoff_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The server-generated handoff attempt identifier. Required.""" + edge_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The configured edge selected for this handoff. Required.""" + from_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source node identifier or ``$entrypoint``. Required.""" + to_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target node identifier or ``$entrypoint``. Required.""" + from_model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model active before the handoff. Required.""" + to_model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model prepared for the target behavior. Required.""" + tool_call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The function-call identifier that initiated the handoff. Required.""" + node_generation: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source generation for started or aborted events, and the committed target generation for + completed events. Required.""" + reason: Union[str, "_models.VoiceAgentHandoffAbortReason"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Why the handoff ended before target commit. Required. Known values are: \"user_interruption\" + and \"error\".""" + error: Optional["_models.RealtimeServerEventErrorError"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The handoff failure detail when ``reason`` is ``error``.""" + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_ABORTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``session.handoff.aborted``. Required. SESSION_HANDOFF_ABORTED.""" + + @overload + def __init__( + self, + *, + event_id: str, + handoff_id: str, + edge_id: str, + from_node_id: str, + to_node_id: str, + from_model: str, + to_model: str, + tool_call_id: str, + node_generation: int, + reason: Union[str, "_models.VoiceAgentHandoffAbortReason"], + error: Optional["_models.RealtimeServerEventErrorError"] = 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 = VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_ABORTED # type: ignore + + +class VoiceAgentServerEventSessionHandoffCompleted( + RealtimeServerEvent, discriminator="session.handoff.completed" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The ``session.handoff.completed`` server event. + + :ivar event_id: The server-generated event identifier. Required. + :vartype event_id: str + :ivar handoff_id: The server-generated handoff attempt identifier. Required. + :vartype handoff_id: str + :ivar edge_id: The configured edge selected for this handoff. Required. + :vartype edge_id: str + :ivar from_node_id: The source node identifier or ``$entrypoint``. Required. + :vartype from_node_id: str + :ivar to_node_id: The target node identifier or ``$entrypoint``. Required. + :vartype to_node_id: str + :ivar from_model: The model active before the handoff. Required. + :vartype from_model: str + :ivar to_model: The model prepared for the target behavior. Required. + :vartype to_model: str + :ivar tool_call_id: The function-call identifier that initiated the handoff. Required. + :vartype tool_call_id: str + :ivar node_generation: The source generation for started or aborted events, and the committed + target generation for completed events. Required. + :vartype node_generation: int + :ivar prepare_duration_ms: The target-preparation duration. Required. + :vartype prepare_duration_ms: ~datetime.timedelta + :ivar duration_ms: The total handoff duration. Required. + :vartype duration_ms: ~datetime.timedelta + :ivar type: The event type. Always ``session.handoff.completed``. Required. + SESSION_HANDOFF_COMPLETED. + :vartype type: str or ~azure.ai.projects.models.SESSION_HANDOFF_COMPLETED + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The server-generated event identifier. Required.""" + handoff_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The server-generated handoff attempt identifier. Required.""" + edge_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The configured edge selected for this handoff. Required.""" + from_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source node identifier or ``$entrypoint``. Required.""" + to_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target node identifier or ``$entrypoint``. Required.""" + from_model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model active before the handoff. Required.""" + to_model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model prepared for the target behavior. Required.""" + tool_call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The function-call identifier that initiated the handoff. Required.""" + node_generation: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source generation for started or aborted events, and the committed target generation for + completed events. Required.""" + prepare_duration_ms: datetime.timedelta = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """The target-preparation duration. Required.""" + duration_ms: datetime.timedelta = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-milliseconds-int" + ) + """The total handoff duration. Required.""" + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``session.handoff.completed``. Required. SESSION_HANDOFF_COMPLETED.""" + + @overload + def __init__( + self, + *, + event_id: str, + handoff_id: str, + edge_id: str, + from_node_id: str, + to_node_id: str, + from_model: str, + to_model: str, + tool_call_id: str, + node_generation: int, + prepare_duration_ms: datetime.timedelta, + duration_ms: datetime.timedelta, + ) -> 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 = VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_COMPLETED # type: ignore + + +class VoiceAgentServerEventSessionHandoffStarted( + RealtimeServerEvent, discriminator="session.handoff.started" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The ``session.handoff.started`` server event. + + :ivar event_id: The server-generated event identifier. Required. + :vartype event_id: str + :ivar handoff_id: The server-generated handoff attempt identifier. Required. + :vartype handoff_id: str + :ivar edge_id: The configured edge selected for this handoff. Required. + :vartype edge_id: str + :ivar from_node_id: The source node identifier or ``$entrypoint``. Required. + :vartype from_node_id: str + :ivar to_node_id: The target node identifier or ``$entrypoint``. Required. + :vartype to_node_id: str + :ivar from_model: The model active before the handoff. Required. + :vartype from_model: str + :ivar to_model: The model prepared for the target behavior. Required. + :vartype to_model: str + :ivar tool_call_id: The function-call identifier that initiated the handoff. Required. + :vartype tool_call_id: str + :ivar node_generation: The source generation for started or aborted events, and the committed + target generation for completed events. Required. + :vartype node_generation: int + :ivar type: The event type. Always ``session.handoff.started``. Required. + SESSION_HANDOFF_STARTED. + :vartype type: str or ~azure.ai.projects.models.SESSION_HANDOFF_STARTED + """ + + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The server-generated event identifier. Required.""" + handoff_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The server-generated handoff attempt identifier. Required.""" + edge_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The configured edge selected for this handoff. Required.""" + from_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source node identifier or ``$entrypoint``. Required.""" + to_node_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The target node identifier or ``$entrypoint``. Required.""" + from_model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model active before the handoff. Required.""" + to_model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model prepared for the target behavior. Required.""" + tool_call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The function-call identifier that initiated the handoff. Required.""" + node_generation: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source generation for started or aborted events, and the committed target generation for + completed events. Required.""" + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_STARTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``session.handoff.started``. Required. SESSION_HANDOFF_STARTED.""" + + @overload + def __init__( + self, + *, + event_id: str, + handoff_id: str, + edge_id: str, + from_node_id: str, + to_node_id: str, + from_model: str, + to_model: str, + tool_call_id: str, + node_generation: 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 = VoiceAgentServerEventTypeExtension.SESSION_HANDOFF_STARTED # type: ignore class VoiceAgentServerEventSessionSubagentAborted( @@ -30739,7 +41108,7 @@ class VoiceAgentServerEventSessionSubagentAborted( :vartype reason: str or ~azure.ai.projects.models.VoiceAgentSubagentAbortReason """ - type: Literal[RealtimeServerEventType.SESSION_SUBAGENT_ABORTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_ABORTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The event type. Always ``session.subagent.aborted``. Required. SESSION_SUBAGENT_ABORTED.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The server-generated event identifier. Required.""" @@ -30775,7 +41144,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_SUBAGENT_ABORTED # type: ignore + self.type = VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_ABORTED # type: ignore class VoiceAgentServerEventSessionSubagentCompleted( @@ -30796,7 +41165,7 @@ class VoiceAgentServerEventSessionSubagentCompleted( :vartype subagent_name: str """ - type: Literal[RealtimeServerEventType.SESSION_SUBAGENT_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_COMPLETED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The event type. Always ``session.subagent.completed``. Required. SESSION_SUBAGENT_COMPLETED.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The server-generated event identifier. Required.""" @@ -30826,7 +41195,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_SUBAGENT_COMPLETED # type: ignore + self.type = VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_COMPLETED # type: ignore class VoiceAgentServerEventSessionSubagentStarted( @@ -30847,7 +41216,7 @@ class VoiceAgentServerEventSessionSubagentStarted( :vartype subagent_name: str """ - type: Literal[RealtimeServerEventType.SESSION_SUBAGENT_STARTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_STARTED] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The event type. Always ``session.subagent.started``. Required. SESSION_SUBAGENT_STARTED.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The server-generated event identifier. Required.""" @@ -30877,7 +41246,148 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.SESSION_SUBAGENT_STARTED # type: ignore + self.type = VoiceAgentServerEventTypeExtension.SESSION_SUBAGENT_STARTED # type: ignore + + +class VoiceAgentServerEventSystemToolArgumentsDelta( + RealtimeServerEvent, discriminator="response.system_tool_arguments.delta" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """An incremental model-argument fragment for a service-managed system tool. + + :ivar type: The event type. Always ``response.system_tool_arguments.delta``. Required. An + incremental fragment of model-generated system-tool arguments. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA + :ivar event_id: The unique identifier of this server event. Required. + :vartype event_id: str + :ivar response_id: The response containing the tool invocation. Required. + :vartype response_id: str + :ivar item_id: The generated tool item's identifier. Required. + :vartype item_id: str + :ivar output_index: The item's zero-based position in the response output. Required. + :vartype output_index: int + :ivar call_id: The invocation identifier. Required. + :vartype call_id: str + :ivar delta: An incremental JSON fragment of the intent arguments. Required. + :vartype delta: str + :ivar obfuscation: Optional padding metadata with no application semantics. + :vartype obfuscation: str + """ + + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``response.system_tool_arguments.delta``. Required. An incremental + fragment of model-generated system-tool arguments.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of this server event. Required.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The response containing the tool invocation. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The generated tool item's identifier. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The item's zero-based position in the response output. Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The invocation identifier. Required.""" + delta: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """An incremental JSON fragment of the intent arguments. Required.""" + obfuscation: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional padding metadata with no application semantics.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + call_id: str, + delta: str, + obfuscation: 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 = VoiceAgentServerEventTypeExtension.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DELTA # type: ignore + + +class VoiceAgentServerEventSystemToolArgumentsDone( + RealtimeServerEvent, discriminator="response.system_tool_arguments.done" +): # pylint: disable=name-too-long,docstring-keyword-should-match-keyword-only + """The completed intent arguments for a system tool, not provider success or a request for a + customer function result. + + :ivar type: The event type. Always ``response.system_tool_arguments.done``. Required. The + complete model-generated system-tool arguments, not a provider outcome. + :vartype type: str or ~azure.ai.projects.models.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE + :ivar event_id: The unique identifier of this server event. Required. + :vartype event_id: str + :ivar response_id: The response containing the tool invocation. Required. + :vartype response_id: str + :ivar item_id: The generated tool item's identifier. Required. + :vartype item_id: str + :ivar output_index: The item's zero-based position in the response output. Required. + :vartype output_index: int + :ivar call_id: The invocation identifier. Required. + :vartype call_id: str + :ivar name: The invoked built-in capability. Required. Known values are: "end_conversation", + "language_detection", "digit_recognition", "transfer", "collect_sms", "collect_dtmf", + "send_dtmf", and "send_sms". + :vartype name: str or ~azure.ai.projects.models.VoiceAgentSystemToolName + :ivar arguments: The complete, unexpanded model arguments as a JSON string. Required. + :vartype arguments: str + """ + + type: Literal[VoiceAgentServerEventTypeExtension.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The event type. Always ``response.system_tool_arguments.done``. Required. The complete + model-generated system-tool arguments, not a provider outcome.""" + event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique identifier of this server event. Required.""" + response_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The response containing the tool invocation. Required.""" + item_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The generated tool item's identifier. Required.""" + output_index: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The item's zero-based position in the response output. Required.""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The invocation identifier. Required.""" + name: Union[str, "_models.VoiceAgentSystemToolName"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The invoked built-in capability. Required. Known values are: \"end_conversation\", + \"language_detection\", \"digit_recognition\", \"transfer\", \"collect_sms\", \"collect_dtmf\", + \"send_dtmf\", and \"send_sms\".""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The complete, unexpanded model arguments as a JSON string. Required.""" + + @overload + def __init__( + self, + *, + event_id: str, + response_id: str, + item_id: str, + output_index: int, + call_id: str, + name: Union[str, "_models.VoiceAgentSystemToolName"], + arguments: 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 = VoiceAgentServerEventTypeExtension.RESPONSE_SYSTEM_TOOL_ARGUMENTS_DONE # type: ignore class VoiceAgentServerEventWarning( @@ -30893,7 +41403,7 @@ class VoiceAgentServerEventWarning( :vartype warning: ~azure.ai.projects.models.VoiceAgentServerEventWarningDetails """ - type: Literal[RealtimeServerEventType.WARNING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + type: Literal[VoiceAgentServerEventTypeExtension.WARNING] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. WARNING.""" event_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Required.""" @@ -30919,7 +41429,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = RealtimeServerEventType.WARNING # type: ignore + self.type = VoiceAgentServerEventTypeExtension.WARNING # type: ignore class VoiceAgentServerEventWarningDetails(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -31130,6 +41640,8 @@ class VoiceAgentSessionResponseConfig(_Model): # pylint: disable=docstring-keyw :vartype interim_response: ~azure.ai.projects.models.VoiceAgentInterimResponseConfig :ivar greeting: A proactive assistant greeting started after session configuration. :vartype greeting: ~azure.ai.projects.models.VoiceAgentGreetingConfig + :ivar handoff: The effective handoff topology and runtime state, when handoff is configured. + :vartype handoff: ~azure.ai.projects.models.VoiceAgentHandoffState :ivar object: The object type. Always ``realtime.session``. Required. Default value is "realtime.session". :vartype object: str @@ -31197,6 +41709,10 @@ class VoiceAgentSessionResponseConfig(_Model): # pylint: disable=docstring-keyw visibility=["read", "create", "update", "delete", "query"] ) """A proactive assistant greeting started after session configuration.""" + handoff: Optional["_models.VoiceAgentHandoffState"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The effective handoff topology and runtime state, when handoff is configured.""" object: Literal["realtime.session"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The object type. Always ``realtime.session``. Required. Default value is \"realtime.session\".""" id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -31229,6 +41745,7 @@ def __init__( metadata: Optional[dict[str, str]] = None, interim_response: Optional["_models.VoiceAgentInterimResponseConfig"] = None, greeting: Optional["_models.VoiceAgentGreetingConfig"] = None, + handoff: Optional["_models.VoiceAgentHandoffState"] = None, expires_at: Optional[datetime.datetime] = None, ) -> None: ... @@ -31572,14 +42089,14 @@ class VoiceAgentStaticInterimResponseConfig( :vartype triggers: list[str or ~azure.ai.projects.models.VoiceAgentInterimResponseTrigger] :ivar latency_threshold_ms: The latency threshold in milliseconds. :vartype latency_threshold_ms: ~datetime.timedelta - :ivar type: Required. Default value is "static_interim_response". - :vartype type: str + :ivar type: Required. Select a static interim response from configured text. + :vartype type: str or ~azure.ai.projects.models.STATIC_INTERIM_RESPONSE :ivar texts: Candidate text values for the interim response. :vartype texts: list[str] """ - type: Literal["static_interim_response"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Default value is \"static_interim_response\".""" + type: Literal[VoiceAgentInterimResponseType.STATIC_INTERIM_RESPONSE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Select a static interim response from configured text.""" texts: Optional[list[str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Candidate text values for the interim response.""" @@ -31601,7 +42118,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "static_interim_response" # type: ignore + self.type = VoiceAgentInterimResponseType.STATIC_INTERIM_RESPONSE # type: ignore class VoiceAgentSubagent(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -31664,38 +42181,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceAgentSubagentConfig(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only - """Configuration for sibling Foundry text agents that a voice agent may consult. - - :ivar subagents: The sibling Foundry text agents, in the same project, that this voice agent - may consult. Required. - :vartype subagents: list[~azure.ai.projects.models.VoiceAgentSubagent] - """ - - subagents: list["_models.VoiceAgentSubagent"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The sibling Foundry text agents, in the same project, that this voice agent may consult. - Required.""" - - @overload - def __init__( - self, - *, - subagents: list["_models.VoiceAgentSubagent"], - ) -> 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 VoiceAgentSubagentResponsePolicy(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Policy for delivering responses while a voice agent waits for a subagent. @@ -31766,20 +42251,104 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class VoiceAgentSystemToolItem( + RealtimeConversationItem, discriminator="system_tool" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Service-generated system-tool intent, not a provider result. Clients cannot create it or + complete it with ``function_call_output``. + + :ivar type: The output-item kind. Always ``system_tool``. Required. A service-managed + system-tool intent, not a provider result. + :vartype type: str or ~azure.ai.projects.models.SYSTEM_TOOL + :ivar id: The identifier of the generated item. + :vartype id: str + :ivar object: The realtime item marker. Default value is "realtime.item". + :vartype object: str + :ivar status: The generation status of the item, not the provider execution outcome. Required. + Known values are: "in_progress", "completed", and "incomplete". + :vartype status: str or ~azure.ai.projects.models.VoiceAgentSystemToolItemStatus + :ivar name: The built-in capability invoked by the model. Required. Known values are: + "end_conversation", "language_detection", "digit_recognition", "transfer", "collect_sms", + "collect_dtmf", "send_dtmf", and "send_sms". + :vartype name: str or ~azure.ai.projects.models.VoiceAgentSystemToolName + :ivar call_id: The invocation identifier used for correlation and duplicate suppression. + Required. + :vartype call_id: str + :ivar arguments: Original JSON-encoded intent: literals remain visible and references stay + unexpanded. Excludes private values, resolved arguments and executor-only settings. Required. + :vartype arguments: str + :ivar created_at: The Unix timestamp (in seconds) for when the item was persisted. + :vartype created_at: ~datetime.datetime + :ivar response_id: The id of the response that produced this item, when applicable. + :vartype response_id: str + """ + + type: Literal[VoiceAgentConversationItemTypeExtension.SYSTEM_TOOL] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The output-item kind. Always ``system_tool``. Required. A service-managed system-tool intent, + not a provider result.""" + id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The identifier of the generated item.""" + object: Optional[Literal["realtime.item"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The realtime item marker. Default value is \"realtime.item\".""" + status: Union[str, "_models.VoiceAgentSystemToolItemStatus"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The generation status of the item, not the provider execution outcome. Required. Known values + are: \"in_progress\", \"completed\", and \"incomplete\".""" + name: Union[str, "_models.VoiceAgentSystemToolName"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The built-in capability invoked by the model. Required. Known values are: \"end_conversation\", + \"language_detection\", \"digit_recognition\", \"transfer\", \"collect_sms\", \"collect_dtmf\", + \"send_dtmf\", and \"send_sms\".""" + call_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The invocation identifier used for correlation and duplicate suppression. Required.""" + arguments: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Original JSON-encoded intent: literals remain visible and references stay unexpanded. Excludes + private values, resolved arguments and executor-only settings. Required.""" + created_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The Unix timestamp (in seconds) for when the item was persisted.""" + response_id: Optional[str] = rest_field(visibility=["read"]) + """The id of the response that produced this item, when applicable.""" + + @overload + def __init__( + self, + *, + status: Union[str, "_models.VoiceAgentSystemToolItemStatus"], + name: Union[str, "_models.VoiceAgentSystemToolName"], + call_id: str, + arguments: str, + id: Optional[str] = None, # pylint: disable=redefined-builtin + object: Optional[Literal["realtime.item"]] = 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 = VoiceAgentConversationItemTypeExtension.SYSTEM_TOOL # type: ignore + + class VoiceAgentTemplateGreetingConfig( VoiceAgentGreetingConfig, discriminator="template" ): # pylint: disable=docstring-keyword-should-match-keyword-only """A deterministic greeting rendered with the voice agent's structured inputs and synthesized without model-authored generation. - :ivar type: Required. Default value is "template". - :vartype type: str + :ivar type: Required. Speak a deterministic greeting rendered from a text template. + :vartype type: str or ~azure.ai.projects.models.TEMPLATE :ivar text: The Handlebars text template spoken at session start. Required. :vartype text: str """ - type: Literal["template"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Default value is \"template\".""" + type: Literal[VoiceAgentGreetingMode.TEMPLATE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Speak a deterministic greeting rendered from a text template.""" text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The Handlebars text template spoken at session start. Required.""" @@ -31799,7 +42368,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "template" # type: ignore + self.type = VoiceAgentGreetingMode.TEMPLATE # type: ignore class VoiceAgentToolboxTool( @@ -31808,8 +42377,9 @@ class VoiceAgentToolboxTool( """A reference to a Foundry toolbox, which is a versioned bundle of tools executed through its MCP endpoint. - :ivar type: The type of the tool. Always ``toolbox``. Required. Default value is "toolbox". - :vartype type: str + :ivar type: The type of the tool. Always ``toolbox``. Required. A reference to a Foundry + toolbox. + :vartype type: str or ~azure.ai.projects.models.TOOLBOX :ivar toolbox_name: The name of the toolbox to attach. Required. :vartype toolbox_name: str :ivar toolbox_version: The immutable version of the toolbox to attach. Required. @@ -31819,8 +42389,8 @@ class VoiceAgentToolboxTool( :vartype response_scheduling: str or ~azure.ai.projects.models.VoiceAgentToolResponseScheduling """ - type: Literal["toolbox"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the tool. Always ``toolbox``. Required. Default value is \"toolbox\".""" + type: Literal[VoiceAgentToolType.TOOLBOX] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the tool. Always ``toolbox``. Required. A reference to a Foundry toolbox.""" toolbox_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The name of the toolbox to attach. Required.""" toolbox_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -31849,7 +42419,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "toolbox" # type: ignore + self.type = VoiceAgentToolType.TOOLBOX # type: ignore class VoiceAgentTranscriptionPhrase(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -31955,6 +42525,196 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class VoiceAgentTransferDestination(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The canonical system-tool transfer destination. + + :ivar type: The destination format: phone_number for an E.164 number, teams for a Teams + identifier, or sip for a SIP URI. Required. Known values are: "phone_number", "teams", and + "sip". + :vartype type: str or ~azure.ai.projects.models.VoiceAgentTransferDestinationType + :ivar value: The concrete address. Phone numbers use E.164; Teams and SIP identifiers are + validated against the selected provider's capabilities. Required. + :vartype value: str + """ + + type: Union[str, "_models.VoiceAgentTransferDestinationType"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The destination format: phone_number for an E.164 number, teams for a Teams identifier, or sip + for a SIP URI. Required. Known values are: \"phone_number\", \"teams\", and \"sip\".""" + value: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The concrete address. Phone numbers use E.164; Teams and SIP identifiers are validated against + the selected provider's capabilities. Required.""" + + @overload + def __init__( + self, + *, + type: Union[str, "_models.VoiceAgentTransferDestinationType"], + value: 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 VoiceAgentTransferRouting(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """The configured transfer routing policy. The model selects a target name, not destinations or + routing settings. + + :ivar strategy: The routing strategy. Current native Telephony transfer supports ACS sequential + and random routing only. Required. Known values are: "sequential", "random", and "parallel". + :vartype strategy: str or ~azure.ai.projects.models.VoiceAgentTransferStrategy + :ivar ring_timeout_seconds: Per-destination ring timeout in seconds, from 1 to 300. If omitted, + the service defaults to 20 seconds. Must not exceed the tool's timeout_seconds. ACS allows at + most 180 seconds. + :vartype ring_timeout_seconds: ~datetime.timedelta + """ + + strategy: Union[str, "_models.VoiceAgentTransferStrategy"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The routing strategy. Current native Telephony transfer supports ACS sequential and random + routing only. Required. Known values are: \"sequential\", \"random\", and \"parallel\".""" + ring_timeout_seconds: Optional[datetime.timedelta] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="duration-seconds-int" + ) + """Per-destination ring timeout in seconds, from 1 to 300. If omitted, the service defaults to 20 + seconds. Must not exceed the tool's timeout_seconds. ACS allows at most 180 seconds.""" + + @overload + def __init__( + self, + *, + strategy: Union[str, "_models.VoiceAgentTransferStrategy"], + ring_timeout_seconds: Optional[datetime.timedelta] = 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 VoiceAgentTransferSystemTool( + VoiceAgentSystemTool, discriminator="transfer" +): # pylint: disable=docstring-keyword-should-match-keyword-only + """Requests a transfer to an explicitly configured logical target. + + :ivar type: The type of the tool. Always ``system``. Required. A service-managed control that + acts on the active voice session. + :vartype type: str or ~azure.ai.projects.models.SYSTEM + :ivar description: An optional description of the system tool. + :vartype description: str + :ivar timeout_seconds: Execution timeout, from 1 to 300 seconds. If omitted, the service + defaults to 60 seconds. + :vartype timeout_seconds: ~datetime.timedelta + :ivar name: The service-managed control action. Always ``transfer``. Required. Requests a + transfer to an explicitly configured logical target. + :vartype name: str or ~azure.ai.projects.models.TRANSFER + :ivar require_handoff: Require a non-blank handoff summary in each model-generated transfer + call. Defaults to false; does not guarantee delivery to the recipient. + :vartype require_handoff: bool + :ivar targets: The non-empty set of logical targets that the model may select. Required. + :vartype targets: list[~azure.ai.projects.models.VoiceAgentTransferTarget] + """ + + __mapping__: dict[str, _Model] = {} + name: Literal[VoiceAgentSystemToolName.TRANSFER] = rest_discriminator(name="name", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The service-managed control action. Always ``transfer``. Required. Requests a transfer to an + explicitly configured logical target.""" + require_handoff: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Require a non-blank handoff summary in each model-generated transfer call. Defaults to false; + does not guarantee delivery to the recipient.""" + targets: list["_models.VoiceAgentTransferTarget"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The non-empty set of logical targets that the model may select. Required.""" + + @overload + def __init__( + self, + *, + targets: list["_models.VoiceAgentTransferTarget"], + description: Optional[str] = None, + timeout_seconds: Optional[datetime.timedelta] = None, + require_handoff: 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) + self.name = VoiceAgentSystemToolName.TRANSFER # type: ignore + + +class VoiceAgentTransferTarget(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only + """A configured logical transfer target. Only its name and description are model-visible; + destinations and routing are executor settings. + + :ivar name: The non-blank logical target name. Names must be unique after trimming within the + transfer tool. Required. + :vartype name: str + :ivar description: A description that helps the model select this target. + :vartype description: str + :ivar destinations: The concrete destinations for this transfer target. Required. + :vartype destinations: list[~azure.ai.projects.models.VoiceAgentTransferDestination] + :ivar routing: The trusted routing policy for this target. Required. + :vartype routing: ~azure.ai.projects.models.VoiceAgentTransferRouting + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The non-blank logical target name. Names must be unique after trimming within the transfer + tool. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A description that helps the model select this target.""" + destinations: list["_models.VoiceAgentTransferDestination"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The concrete destinations for this transfer target. Required.""" + routing: "_models.VoiceAgentTransferRouting" = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The trusted routing policy for this target. Required.""" + + @overload + def __init__( + self, + *, + name: str, + destinations: list["_models.VoiceAgentTransferDestination"], + routing: "_models.VoiceAgentTransferRouting", + 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 VoiceAudioItem(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """Metadata for a single conversation item's audio segment. For bring-your-own-storage (BYOS), the response includes ``blob_uri``, a direct customer-storage URI without a SAS token, that the @@ -32142,13 +42902,13 @@ class VoiceConversationEngine(_Model): # pylint: disable=docstring-keyword-shou You probably want to use the sub-classes and not this class directly. Known sub-classes are: VoiceHostedAgentConversationEngine - :ivar type: The conversation engine type. Required. Default value is None. - :vartype type: str + :ivar type: The conversation engine type. Required. "hosted_agent" + :vartype type: str or ~azure.ai.projects.models.VoiceConversationEngineType """ __mapping__: dict[str, _Model] = {} type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The conversation engine type. Required. Default value is None.""" + """The conversation engine type. Required. \"hosted_agent\"""" @overload def __init__( @@ -32271,9 +43031,9 @@ class VoiceHostedAgentConversationEngine( API version ``v1``. Declaring ``invocations_ws`` is optional and does not substitute for ``voice_conversation_engine``. - :ivar type: Selects a hosted Foundry agent as the conversation engine. Required. Default value - is "hosted_agent". - :vartype type: str + :ivar type: Selects a hosted Foundry agent as the conversation engine. Required. Use a hosted + Foundry agent to handle the conversation. + :vartype type: str or ~azure.ai.projects.models.HOSTED_AGENT :ivar name: The non-empty DNS-like name of the target hosted text agent in the same project. Required. :vartype name: str @@ -32283,9 +43043,9 @@ class VoiceHostedAgentConversationEngine( :vartype version: str """ - type: Literal["hosted_agent"] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Selects a hosted Foundry agent as the conversation engine. Required. Default value is - \"hosted_agent\".""" + type: Literal[VoiceConversationEngineType.HOSTED_AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Selects a hosted Foundry agent as the conversation engine. Required. Use a hosted Foundry agent + to handle the conversation.""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The non-empty DNS-like name of the target hosted text agent in the same project. Required.""" version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -32310,7 +43070,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = "hosted_agent" # type: ignore + self.type = VoiceConversationEngineType.HOSTED_AGENT # type: ignore class VoiceRecording(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -32390,26 +43150,39 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class VoiceRecordingChannelLayout(_Model): # pylint: disable=docstring-missing-param +class VoiceRecordingChannelLayout(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only """The role assigned to each channel of a merged stereo voice recording. - :ivar left: The role carried on the left channel. Always ``user``. Required. Default value is - "user". - :vartype left: str - :ivar right: The role carried on the right channel. Always ``agent``. Required. Default value - is "agent". - :vartype right: str + :ivar left: The role carried on the left channel. Always ``user``. Required. Audio produced by + the user. + :vartype left: str or ~azure.ai.projects.models.USER + :ivar right: The role carried on the right channel. Always ``agent``. Required. Audio produced + by the agent. + :vartype right: str or ~azure.ai.projects.models.AGENT """ - left: Literal["user"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The role carried on the left channel. Always ``user``. Required. Default value is \"user\".""" - right: Literal["agent"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The role carried on the right channel. Always ``agent``. Required. Default value is \"agent\".""" + left: Literal[VoiceAudioRole.USER] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The role carried on the left channel. Always ``user``. Required. Audio produced by the user.""" + right: Literal[VoiceAudioRole.AGENT] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The role carried on the right channel. Always ``agent``. Required. Audio produced by the agent.""" + + @overload + def __init__( + self, + *, + left: Literal[VoiceAudioRole.USER], + right: Literal[VoiceAudioRole.AGENT], + ) -> 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.left: Literal["user"] = "user" - self.right: Literal["agent"] = "agent" class VoiceResponse(_Model): # pylint: disable=docstring-keyword-should-match-keyword-only @@ -32900,7 +43673,9 @@ class WebSearchTool(Tool, discriminator="web_search"): # pylint: disable=docstr :vartype external_web_access: bool :ivar filters: :vartype filters: ~azure.ai.projects.models.WebSearchToolFilters - :ivar user_location: + :ivar user_location: The approximate location of the user. If omitted or null, defaults to the + United States. To avoid this fallback, pass ``{"type": "approximate"}`` without location + fields. To localize results, provide the relevant location fields. :vartype user_location: ~azure.ai.projects.models.WebSearchApproximateLocation :ivar search_context_size: High level guidance for the amount of context window space to use for the search. One of ``low``, ``medium``, or ``high``. ``medium`` is the default. Is one of @@ -32931,6 +43706,9 @@ class WebSearchTool(Tool, discriminator="web_search"): # pylint: disable=docstr user_location: Optional["_models.WebSearchApproximateLocation"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) + """The approximate location of the user. If omitted or null, defaults to the United States. To + avoid this fallback, pass ``{\"type\": \"approximate\"}`` without location fields. To localize + results, provide the relevant location fields.""" search_context_size: Optional[Literal["low", "medium", "high"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -32998,7 +43776,9 @@ class WebSearchToolboxTool( :vartype external_web_access: bool :ivar filters: :vartype filters: ~azure.ai.projects.models.WebSearchToolFilters - :ivar user_location: + :ivar user_location: The approximate location of the user. If omitted or null, defaults to the + United States. To avoid this fallback, pass ``{"type": "approximate"}`` without location + fields. To localize results, provide the relevant location fields. :vartype user_location: ~azure.ai.projects.models.WebSearchApproximateLocation :ivar search_context_size: High level guidance for the amount of context window space to use for the search. One of ``low``, ``medium``, or ``high``. ``medium`` is the default. Is one of @@ -33020,6 +43800,9 @@ class WebSearchToolboxTool( user_location: Optional["_models.WebSearchApproximateLocation"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) + """The approximate location of the user. If omitted or null, defaults to the United States. To + avoid this fallback, pass ``{\"type\": \"approximate\"}`` without location fields. To localize + results, provide the relevant location fields.""" search_context_size: Optional[Literal["low", "medium", "high"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) 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 31880837c921..8ea15a66086c 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 @@ -4685,6 +4685,274 @@ def build_beta_voice_agents_conversations_download_audio_request( # pylint: dis return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) +def build_beta_voice_agents_live_conversations_list_request( # pylint: disable=name-too-long + agent_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 = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_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_voice_agents_live_conversations_get_request( # pylint: disable=name-too-long + agent_name: str, conversation_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 = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_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_voice_agents_live_conversations_delete_request( # pylint: disable=name-too-long + agent_name: str, conversation_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 = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_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_voice_agents_live_conversations_list_items_request( # pylint: disable=name-too-long + agent_name: str, + conversation_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 {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}/items" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_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 + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_voice_agents_live_conversations_get_item_request( # pylint: disable=name-too-long + agent_name: str, conversation_id: str, item_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 = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}/items/{item_id}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_id, "str"), + "item_id": _SERIALIZER.url("item_id", item_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_voice_agents_live_conversations_get_audio_item_request( # pylint: disable=name-too-long + agent_name: str, conversation_id: str, item_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 = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}/items/{item_id}/audio" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_id, "str"), + "item_id": _SERIALIZER.url("item_id", item_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_voice_agents_live_conversations_download_audio_item_request( # pylint: disable=name-too-long + agent_name: str, conversation_id: str, item_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", "audio/wav") + + # Construct URL + _url = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}/items/{item_id}/audio/content" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_id, "str"), + "item_id": _SERIALIZER.url("item_id", item_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_voice_agents_live_conversations_get_audio_request( # pylint: disable=name-too-long + agent_name: str, conversation_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 = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}/audio" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_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_voice_agents_live_conversations_download_audio_request( # pylint: disable=name-too-long + agent_name: str, conversation_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", "audio/wav") + + # Construct URL + _url = "/agents/{agent_name}/endpoint/protocols/voice/live/conversations/{conversation_id}/audio/content" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "conversation_id": _SERIALIZER.url("conversation_id", conversation_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_voice_agents_telephony_create_binding_request( # pylint: disable=name-too-long agent_name: str, **kwargs: Any ) -> HttpRequest: @@ -4724,7 +4992,6 @@ def build_beta_voice_agents_telephony_list_bindings_request( # pylint: disable= agent_name: str, *, provider: Optional[Union[str, _models.TelephonyProvider]] = None, - status: Optional[Union[str, _models.TelephonyBindingStatus]] = None, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, after: Optional[str] = None, @@ -4748,8 +5015,6 @@ def build_beta_voice_agents_telephony_list_bindings_request( # pylint: disable= # Construct parameters if provider is not None: _params["provider"] = _SERIALIZER.query("provider", provider, "str") - if status is not None: - _params["status"] = _SERIALIZER.query("status", status, "str") if limit is not None: _params["limit"] = _SERIALIZER.query("limit", limit, "int") if order is not None: @@ -5067,7 +5332,7 @@ def build_beta_voice_agents_telephony_create_call_job_request( # pylint: disabl accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/agents/{agent_name}/telephony/call_jobs" + _url = "/agents/{agent_name}/telephony_call_jobs" path_format_arguments = { "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), } @@ -5086,17 +5351,84 @@ def build_beta_voice_agents_telephony_create_call_job_request( # pylint: disabl return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_voice_agents_telephony_get_call_job_request( # pylint: disable=name-too-long - agent_name: str, call_job_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) +def build_beta_voice_agents_telephony_list_call_jobs_request( # pylint: disable=name-too-long + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.TelephonyCallJobStatus]] = None, + campaign_name: Optional[str] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/agents/{agent_name}/telephony_call_jobs" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_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") + if status is not None: + _params["status"] = _SERIALIZER.query("status", status, "str") + if campaign_name is not None: + _params["campaign_name"] = _SERIALIZER.query("campaign_name", campaign_name, "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_voice_agents_telephony_delete_call_job_request( # pylint: disable=name-too-long + agent_name: str, call_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 = "/agents/{agent_name}/telephony_call_jobs/{call_job_id}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "call_job_id": _SERIALIZER.url("call_job_id", call_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) + + +def build_beta_voice_agents_telephony_get_call_job_request( # pylint: disable=name-too-long + agent_name: str, call_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 = "/agents/{agent_name}/telephony/call_jobs/{call_job_id}" + _url = "/agents/{agent_name}/telephony_call_jobs/{call_job_id}" path_format_arguments = { "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), "call_job_id": _SERIALIZER.url("call_job_id", call_job_id, "str"), @@ -5123,7 +5455,7 @@ def build_beta_voice_agents_telephony_cancel_call_job_request( # pylint: disabl accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/agents/{agent_name}/telephony/call_jobs/{call_job_id}:cancel" + _url = "/agents/{agent_name}/telephony_call_jobs/{call_job_id}:cancel" path_format_arguments = { "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), "call_job_id": _SERIALIZER.url("call_job_id", call_job_id, "str"), @@ -5146,145 +5478,336 @@ def build_beta_voice_agents_telephony_cancel_call_job_request( # pylint: disabl return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class BetaOperations: # pylint: disable=docstring-missing-param,too-many-instance-attributes - """ - .. warning:: - **DO NOT** instantiate this class directly. +def build_beta_voice_agents_campaigns_create_request( # pylint: disable=name-too-long + agent_name: str, + campaign_name: str, + *, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`beta` attribute. - """ + 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") - 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") + # Construct URL + _url = "/agents/{agent_name}/telephony_campaigns/{campaign_name}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "campaign_name": _SERIALIZER.url("campaign_name", campaign_name, "str"), + } - self.voice_agents = BetaVoiceAgentsOperations(self._client, self._config, self._serialize, self._deserialize) - self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) - self.agent_insight_monitors = BetaAgentInsightMonitorsOperations( - 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.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: # pylint: disable=docstring-missing-param,too-many-public-methods - """ - .. warning:: - **DO NOT** instantiate this class directly. + # 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") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["If-Match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) + if if_none_match is not None: + _headers["if-none-match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`agents` attribute. - """ + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **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") - @distributed_trace - def get(self, agent_name: str, **kwargs: Any) -> _models.AgentDetails: - """Get an agent. +def build_beta_voice_agents_campaigns_get_request( # pylint: disable=name-too-long + agent_name: str, campaign_name: str, *, operation_id: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - Retrieves an agent definition by its unique name. + 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 = "/agents/{agent_name}/telephony_campaigns/{campaign_name}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "campaign_name": _SERIALIZER.url("campaign_name", campaign_name, "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 + if operation_id is not None: + _params["operation_id"] = _SERIALIZER.query("operation_id", operation_id, "str") + _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 + _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="GET", 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_voice_agents_campaigns_list_request( # pylint: disable=name-too-long + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.TelephonyCampaignStatus]] = None, + **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()) + 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 = "/agents/{agent_name}/telephony_campaigns" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + } - return deserialized # type: ignore + _url: str = _url.format(**path_format_arguments) # type: ignore - @distributed_trace - def delete(self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any) -> _models.DeleteAgentResponse: - """Delete an agent. + # 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") + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - 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. + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - :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. The service defaults to - ``false`` if a value is not specified by the caller. 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 = { + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_voice_agents_campaigns_cancel_request( # pylint: disable=name-too-long + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: 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 = "/agents/{agent_name}/telephony_campaigns/{campaign_name}:cancel" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "campaign_name": _SERIALIZER.url("campaign_name", campaign_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 operation_id is not None: + _headers["Operation-Id"] = _SERIALIZER.header("operation_id", operation_id, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["If-Match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) + if if_none_match is not None: + _headers["if-none-match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_voice_agents_campaigns_delete_request( # pylint: disable=name-too-long + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: 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")) + # Construct URL + _url = "/agents/{agent_name}/telephony_campaigns/{campaign_name}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "campaign_name": _SERIALIZER.url("campaign_name", campaign_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 operation_id is not None: + _headers["Operation-Id"] = _SERIALIZER.header("operation_id", operation_id, "str") + if_match = prep_if_match(etag, match_condition) + if if_match is not None: + _headers["If-Match"] = _SERIALIZER.header("if_match", if_match, "str") + if_none_match = prep_if_none_match(etag, match_condition) + if if_none_match is not None: + _headers["if-none-match"] = _SERIALIZER.header("if_none_match", if_none_match, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_voice_agents_campaigns_list_validation_errors_request( # pylint: disable=name-too-long + agent_name: str, + campaign_name: str, + *, + limit: Optional[int] = None, + after: Optional[str] = None, + before: Optional[str] = None, + order: Optional[Union[str, _models.PageOrder]] = 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 = "/agents/{agent_name}/telephony_campaigns/{campaign_name}/validation_errors" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "campaign_name": _SERIALIZER.url("campaign_name", campaign_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 after is not None: + _params["after"] = _SERIALIZER.query("after", after, "str") + if before is not None: + _params["before"] = _SERIALIZER.query("before", before, "str") + if order is not None: + _params["order"] = _SERIALIZER.query("order", order, "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_voice_agents_campaigns_get_operation_request( # pylint: disable=name-too-long + agent_name: str, campaign_name: str, operation_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 = "/agents/{agent_name}/telephony_campaigns/{campaign_name}/operations/{operation_id}" + path_format_arguments = { + "agent_name": _SERIALIZER.url("agent_name", agent_name, "str"), + "campaign_name": _SERIALIZER.url("campaign_name", campaign_name, "str"), + "operation_id": _SERIALIZER.url("operation_id", operation_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) + + +class BetaOperations: # pylint: disable=docstring-missing-param,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.voice_agents = BetaVoiceAgentsOperations(self._client, self._config, self._serialize, self._deserialize) + self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) + self.agent_insight_monitors = BetaAgentInsightMonitorsOperations( + 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.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) + + +class AgentsOperations: # pylint: disable=docstring-missing-param,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") + + @distributed_trace + def get(self, agent_name: str, **kwargs: Any) -> _models.AgentDetails: + """Get an agent. + + Retrieves an agent definition by its unique name. + + :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, @@ -5295,11 +5818,10 @@ def delete(self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteAgentResponse] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) - _request = build_agents_delete_request( + _request = build_agents_get_request( agent_name=agent_name, - force=force, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5333,7 +5855,7 @@ def delete(self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteAgentResponse, response.json()) + deserialized = _deserialize(_models.AgentDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -5341,45 +5863,24 @@ def delete(self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any 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"]: - """List agents. + def delete(self, agent_name: str, *, force: Optional[bool] = None, **kwargs: Any) -> _models.DeleteAgentResponse: + """Delete an agent. - Returns a paged collection of agent resources. + 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. - :keyword kind: Filter agents by kind. If not provided, all agents are returned. Known values - are: "prompt", "hosted", "workflow", "external", and "voice". 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] + :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. The service defaults to + ``false`` if a value is not specified by the caller. 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: """ - _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, @@ -5388,11 +5889,107 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _request = build_agents_list_request( - kind=kind, - limit=limit, + 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"]: + """List agents. + + Returns a paged collection of agent resources. + + :keyword kind: Filter agents by kind. If not provided, all agents are returned. Known values + are: "prompt", "hosted", "workflow", "external", and "voice". 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, + limit=limit, order=order, after=_continuation_token, before=before, @@ -7075,7 +7672,9 @@ def get_session_log_stream( Each SSE frame contains: * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) + * `data`: a plain-text log line (currently JSON-formatted, but the schema + is not contractual and may include additional keys or change format + over time — clients should treat it as an opaque string) Example SSE frames: @@ -13895,9 +14494,15 @@ def __init__(self, *args, **kwargs) -> None: self.conversations = BetaVoiceAgentsConversationsOperations( self._client, self._config, self._serialize, self._deserialize ) + self.live_conversations = BetaVoiceAgentsLiveConversationsOperations( + self._client, self._config, self._serialize, self._deserialize + ) self.telephony = BetaVoiceAgentsTelephonyOperations( self._client, self._config, self._serialize, self._deserialize ) + self.campaigns = BetaVoiceAgentsCampaignsOperations( + self._client, self._config, self._serialize, self._deserialize + ) class BetaAgentsOperations: # pylint: disable=docstring-missing-param @@ -21082,33 +21687,1785 @@ def get_next(next_link=None): return ItemPaged(get_next, extract_data) -class BetaSkillsOperations: # pylint: disable=docstring-missing-param - """ - .. warning:: - **DO NOT** instantiate this class directly. +class BetaSkillsOperations: # pylint: disable=docstring-missing-param + """ + .. 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") + + @distributed_trace + def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: + """Retrieve a skill. + + Retrieves the specified skill and its current configuration. + + :param name: The unique name of the skill. Required. + :type name: str + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails + :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.SkillDetails] = kwargs.pop("cls", None) + + _request = build_beta_skills_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) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.SkillDetails"]: + """List skills. + + Returns the skills available in the current project. + + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of SkillDetails + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillDetails] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_skills_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.SkillDetails], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _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 update( + self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Update a skill. + + Modifies the specified skill's configuration. + + :param name: The name of the skill to update. Required. + :type name: str + :keyword default_version: The version identifier that the skill should point to. When set, the + skill'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: 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.SkillDetails: + """Update a skill. + + Modifies the specified skill's configuration. + + :param name: The name of the skill to update. Required. + :type name: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Update a skill. + + Modifies the specified skill's configuration. + + :param name: The name of the skill to update. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails + :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.SkillDetails: + """Update a skill. + + Modifies the specified skill's configuration. + + :param name: The name of the skill 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 skill should point to. When set, the + skill's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: 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 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_skills_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.SkillDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: + """Delete a skill. + + Removes the specified skill and its associated versions. + + :param name: The unique name of the skill. Required. + :type name: str + :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 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.DeleteSkillResult] = kwargs.pop("cls", None) + + _request = build_beta_skills_delete_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DeleteSkillResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def create( + self, + name: str, + *, + content_type: str = "application/json", + inline_content: Optional[_models.SkillInlineContent] = None, + default: Optional[bool] = None, + **kwargs: Any + ) -> _models.SkillVersion: + """Create a new version of a skill. + + Creates a new version of a skill. If the skill does not exist, it will be created. + + :param name: The name of the skill. If the skill does not exist, it will be created. 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 inline_content: Inline skill content for simple skills without file uploads. + Foundry-specific extension. Default value is None. + :paramtype inline_content: ~azure.ai.projects.models.SkillInlineContent + :keyword default: Whether to set this version as the default. Default value is None. + :paramtype default: bool + :return: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillVersion: + """Create a new version of a skill. + + Creates a new version of a skill. If the skill does not exist, it will be created. + + :param name: The name of the skill. If the skill 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: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillVersion: + """Create a new version of a skill. + + Creates a new version of a skill. If the skill does not exist, it will be created. + + :param name: The name of the skill. If the skill 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: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + inline_content: Optional[_models.SkillInlineContent] = None, + default: Optional[bool] = None, + **kwargs: Any + ) -> _models.SkillVersion: + """Create a new version of a skill. + + Creates a new version of a skill. If the skill does not exist, it will be created. + + :param name: The name of the skill. If the skill 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 inline_content: Inline skill content for simple skills without file uploads. + Foundry-specific extension. Default value is None. + :paramtype inline_content: ~azure.ai.projects.models.SkillInlineContent + :keyword default: Whether to set this version as the default. Default value is None. + :paramtype default: bool + :return: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :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.SkillVersion] = kwargs.pop("cls", None) + + if body is _Unset: + body = {"default": default, "inline_content": inline_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_skills_create_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.SkillVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def create_from_files( + self, name: str, content: _models.CreateSkillVersionFromFilesBody, **kwargs: Any + ) -> _models.SkillVersion: + """Create a skill version from uploaded files. + + Creates a new version of a skill from uploaded files via multipart form data. + + :param name: The name of the skill. Required. + :type name: str + :param content: The multipart request content. Required. + :type content: ~azure.ai.projects.models.CreateSkillVersionFromFilesBody + :return: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_from_files(self, name: str, content: JSON, **kwargs: Any) -> _models.SkillVersion: + """Create a skill version from uploaded files. + + Creates a new version of a skill from uploaded files via multipart form data. + + :param name: The name of the skill. Required. + :type name: str + :param content: The multipart request content. Required. + :type content: JSON + :return: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_from_files( + self, name: str, content: Union[_models.CreateSkillVersionFromFilesBody, JSON], **kwargs: Any + ) -> _models.SkillVersion: + """Create a skill version from uploaded files. + + Creates a new version of a skill from uploaded files via multipart form data. + + :param name: The name of the skill. Required. + :type name: str + :param content: The multipart request content. Is either a CreateSkillVersionFromFilesBody type + or a JSON type. Required. + :type content: ~azure.ai.projects.models.CreateSkillVersionFromFilesBody or JSON + :return: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :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.SkillVersion] = kwargs.pop("cls", None) + + _body = content.as_dict() if isinstance(content, _Model) else content + _file_fields: list[str] = ["files"] + _data_fields: list[str] = ["default"] + _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + + _request = build_beta_skills_create_from_files_request( + name=name, + 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.SkillVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_versions( + self, + name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.SkillVersion"]: + """List skill versions. + + Returns the available versions for the specified skill. + + :param name: The name of the skill 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 SkillVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillVersion] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.SkillVersion]] = 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_versions_request( + name=name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.SkillVersion], + 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.SkillVersion: + """Retrieve a specific version of a skill. + + Retrieves the specified version of a skill by name and version identifier. + + :param name: The name of the skill. Required. + :type name: str + :param version: The version identifier to retrieve. Required. + :type version: str + :return: SkillVersion. The SkillVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillVersion + :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.SkillVersion] = kwargs.pop("cls", None) + + _request = build_beta_skills_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.SkillVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: + """Download the zip content for the default version of a skill. + + Downloads the zip content for the default version of a skill. + + :param name: The name of the skill. Required. + :type name: 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_skills_download_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", 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["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def download_version(self, name: str, version: str, **kwargs: Any) -> Iterator[bytes]: + """Download the zip content for a specific version of a skill. + + Downloads the zip content for a specific version of a skill. + + :param name: The name of the skill. Required. + :type name: str + :param version: The version to download content for. Required. + :type 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_skills_download_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", 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["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete_version(self, name: str, version: str, **kwargs: Any) -> _models.DeleteSkillVersionResult: + """Delete a specific version of a skill. + + Removes the specified version of a skill. + + :param name: The name of the skill. Required. + :type name: str + :param version: The version identifier to delete. Required. + :type version: str + :return: DeleteSkillVersionResult. The DeleteSkillVersionResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillVersionResult + :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.DeleteSkillVersionResult] = kwargs.pop("cls", None) + + _request = build_beta_skills_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) + + _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.DeleteSkillVersionResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +class BetaVoiceAgentsConversationsOperations: # pylint: disable=docstring-missing-param + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`conversations` 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( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.VoiceConversation"]: + """List voice agent conversations. + + Returns the conversations persisted for the specified voice agent endpoint. Conversations are + present when the session's effective ``store`` setting is ``true``, whether inherited from the + agent definition or enabled by the WebSocket session override. + + :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 VoiceConversation + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.VoiceConversation] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.VoiceConversation]] = 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_voice_agents_conversations_list_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.VoiceConversation], + 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(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceConversation: + """Get a voice agent conversation. + + Retrieves a single conversation recorded for the specified voice agent endpoint by its id. + Returns ``404`` when the conversation was not persisted (``store = false``) or does not exist. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation to retrieve. Required. + :type conversation_id: str + :return: VoiceConversation. The VoiceConversation is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceConversation + :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.VoiceConversation] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_conversations_get_request( + agent_name=agent_name, + conversation_id=conversation_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) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.VoiceConversation, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete( # pylint: disable=inconsistent-return-statements + self, agent_name: str, conversation_id: str, **kwargs: Any + ) -> None: + """Delete a voice agent conversation. + + Deletes a conversation and all of its stored data — responses, items, and any audio (cascade). + This is the customer's explicit data-deletion control for voice conversations. + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation to delete. Required. + :type conversation_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_voice_agents_conversations_delete_request( + agent_name=agent_name, + conversation_id=conversation_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 + + @distributed_trace + def list_responses( + self, + agent_name: str, + conversation_id: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.VoiceResponse"]: + """List responses in a voice agent conversation. + + Returns a paged collection of the responses (model inference turns) recorded for the specified + conversation. The per-response ``output`` projection may be omitted here; use the + response-items route for the canonical paged output. Returns ``404`` when the conversation was + not persisted (``store = false``). + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation whose responses are listed. Required. + :type conversation_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 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 VoiceResponse + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.VoiceResponse] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.VoiceResponse]] = 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_voice_agents_conversations_list_responses_request( + agent_name=agent_name, + conversation_id=conversation_id, + 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.VoiceResponse], + 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_response( + self, agent_name: str, conversation_id: str, response_id: str, **kwargs: Any + ) -> _models.VoiceResponse: + """Get a voice agent conversation response. + + Retrieves a single response from the specified conversation by its id, including its ``output`` + items, ``usage``, and status. Returns ``404`` when the conversation or response was not + persisted (``store = false``). + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the response. Required. + :type conversation_id: str + :param response_id: The id of the response to retrieve. Required. + :type response_id: str + :return: VoiceResponse. The VoiceResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceResponse + :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.VoiceResponse] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_conversations_get_response_request( + agent_name=agent_name, + conversation_id=conversation_id, + response_id=response_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) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.VoiceResponse, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_response_items( + self, + agent_name: str, + conversation_id: str, + response_id: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.RealtimeConversationItem"]: + """List items produced by a voice agent conversation response. + + Returns a paged collection of the output items produced by a specific response (the response's + output projection). For the complete ordered conversation history — including user input and + client-created tool outputs — use the conversation items route instead. Returns ``404`` when + the conversation or response was not persisted (``store = false``). + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the response. Required. + :type conversation_id: str + :param response_id: The id of the response whose output items are listed. Required. + :type response_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 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 RealtimeConversationItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RealtimeConversationItem] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.RealtimeConversationItem]] = 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_voice_agents_conversations_list_response_items_request( + agent_name=agent_name, + conversation_id=conversation_id, + response_id=response_id, + 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.RealtimeConversationItem], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def list_items( + self, + agent_name: str, + conversation_id: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.RealtimeConversationItem"]: + """List items in a voice agent conversation. + + Returns a paged collection of items — the complete ordered conversation history, including user + input, assistant output, and client-created tool outputs (transcripts + tool events). Returns + ``404`` when the conversation was not persisted (``store = false``). + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation whose items are listed. Required. + :type conversation_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 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 RealtimeConversationItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RealtimeConversationItem] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.RealtimeConversationItem]] = 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_voice_agents_conversations_list_items_request( + agent_name=agent_name, + conversation_id=conversation_id, + 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.RealtimeConversationItem], + 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_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.RealtimeConversationItem: + """Get a voice agent conversation item. + + Retrieves a single item from the specified conversation by its id, including its transcript. An + ``input_audio``/``output_audio`` content part indicates that audio is available for the item; + the canonical per-item audio metadata is the ``/items/{item_id}/audio`` resource, and the bytes + are streamed by ``/items/{item_id}/audio/content``. Returns ``404`` when the conversation or + item was not persisted (``store = false``). + + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the item. Required. + :type conversation_id: str + :param item_id: The id of the conversation item to retrieve. Required. + :type item_id: str + :return: RealtimeConversationItem. The RealtimeConversationItem is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.RealtimeConversationItem + :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.RealtimeConversationItem] = kwargs.pop("cls", None) + + _request = build_beta_voice_agents_conversations_get_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_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) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.RealtimeConversationItem, response.json()) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`skills` attribute. - """ + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + return deserialized # type: ignore @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: - """Retrieve a skill. + def get_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.VoiceAudioItem: + """Get a voice agent conversation item's audio metadata. - Retrieves the specified skill and its current configuration. + Returns metadata for a single conversation item's audio segment, including the common playback + facts (role, format/codec, sample rate, channels, offset, duration) for both Foundry-managed + and bring-your-own-storage (BYOS) recordings; for BYOS the response additionally includes + ``blob_uri``, the URI of the recording in the customer's own storage (no SAS) that the customer + downloads with their own credentials. Requires the conversation to have persisted audio + (``store = true``); returns ``404`` when the conversation, item, or its audio was not + persisted. - :param name: The unique name of the skill. Required. - :type name: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the item. Required. + :type conversation_id: str + :param item_id: The id of the conversation item whose audio metadata is retrieved. Required. + :type item_id: str + :return: VoiceAudioItem. The VoiceAudioItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAudioItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21122,10 +23479,12 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.VoiceAudioItem] = kwargs.pop("cls", None) - _request = build_beta_skills_get_request( - name=name, + _request = build_beta_voice_agents_conversations_get_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -21159,7 +23518,7 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + deserialized = _deserialize(_models.VoiceAudioItem, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -21167,41 +23526,28 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: return deserialized # type: ignore @distributed_trace - def list( - self, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.SkillDetails"]: - """List skills. + def download_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> Iterator[bytes]: + """Stream a voice agent conversation item's audio. - Returns the skills available in the current project. + Streams a single conversation item's audio as a WAV (``audio/wav``) byte stream through the + service (no SAS URL). This route serves Foundry-managed storage only. For + bring-your-own-storage (BYOS) recordings the bytes are not proxied — the caller must download + directly from customer storage using the ``blob_uri`` returned by the item's ``/audio`` + metadata route — so this route returns ``409 Conflict`` for BYOS recordings. Returns ``404`` + when the conversation, item, or its audio was not persisted (``store = false``). - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of SkillDetails - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillDetails] + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the item. Required. + :type conversation_id: str + :param item_id: The id of the conversation item whose audio is streamed. Required. + :type item_id: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -21210,132 +23556,76 @@ def list( } 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) + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - def update( - self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Update a skill. + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - Modifies the specified skill's configuration. + _request = build_beta_voice_agents_conversations_download_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_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 skill to update. Required. - :type name: str - :keyword default_version: The version identifier that the skill should point to. When set, the - skill'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: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + _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 + ) - @overload - def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Update a skill. + response = pipeline_response.http_response - Modifies the specified skill's configuration. + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - :param name: The name of the skill to update. Required. - :type name: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - @overload - def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Update a skill. + deserialized = response.iter_bytes() if _decompress else response.iter_raw() - Modifies the specified skill's configuration. + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore - :param name: The name of the skill to update. Required. - :type name: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails - :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.SkillDetails: - """Update a skill. + def get_generated_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.VoiceGeneratedAudioItem: + """Get a voice agent conversation item's generated audio metadata. - Modifies the specified skill's configuration. + Returns metadata for a conversation item's generated audio. This subordinate artifact is + separate from the canonical heard-audio segment and exists only when playback was interrupted + and the service rendered more audio than the listener heard, including when the response ends + as cancelled. Returns ``404`` when the conversation or item was not persisted, or when no + generated audio exists beyond the heard segment. - :param name: The name of the skill 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 skill should point to. When set, the - skill's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the item. Required. + :type conversation_id: str + :param item_id: The id of the conversation item whose generated audio metadata is retrieved. + Required. + :type item_id: str + :return: VoiceGeneratedAudioItem. The VoiceGeneratedAudioItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceGeneratedAudioItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21346,29 +23636,16 @@ 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.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 + cls: ClsType[_models.VoiceGeneratedAudioItem] = kwargs.pop("cls", None) - _request = build_beta_skills_update_request( - name=name, - content_type=content_type, + _request = build_beta_voice_agents_conversations_get_generated_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -21401,7 +23678,7 @@ def update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + deserialized = _deserialize(_models.VoiceGeneratedAudioItem, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -21409,15 +23686,27 @@ def update( return deserialized # type: ignore @distributed_trace - def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: - """Delete a skill. + def download_generated_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> Iterator[bytes]: + """Stream a voice agent conversation item's generated audio. - Removes the specified skill and its associated versions. + Streams a conversation item's generated audio as a WAV (``audio/wav``) byte stream through the + service. This subordinate artifact exists only when playback was interrupted and the service + rendered more audio than the listener heard, including when the response ends as cancelled. + This route serves Foundry-managed storage only. For bring-your-own-storage (BYOS) recordings + the bytes are not proxied, so this route returns ``409 Conflict``. Returns ``404`` when the + conversation or item was not persisted, or when no generated audio exists beyond the heard + segment. - :param name: The unique name of the skill. Required. - :type name: str - :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillResult + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation that contains the item. Required. + :type conversation_id: str + :param item_id: The id of the conversation item whose generated audio is streamed. Required. + :type item_id: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21431,10 +23720,12 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_skills_delete_request( - name=name, + _request = build_beta_voice_agents_conversations_download_generated_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -21445,7 +23736,7 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: _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 ) @@ -21465,110 +23756,120 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DeleteSkillResult, response.json()) + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @overload - def create( - self, - name: str, - *, - content_type: str = "application/json", - inline_content: Optional[_models.SkillInlineContent] = None, - default: Optional[bool] = None, - **kwargs: Any - ) -> _models.SkillVersion: - """Create a new version of a skill. + @distributed_trace + def get_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceRecording: + """Get a voice agent conversation's merged recording metadata. - Creates a new version of a skill. If the skill does not exist, it will be created. + Returns metadata for the whole-call merged stereo recording (user audio on the left channel, + agent audio on the right). The common metadata (format, sample rate, channels, channel layout, + duration) is returned for both Foundry-managed and bring-your-own-storage (BYOS) recordings; + for BYOS the response additionally includes ``blob_uri``, the URI of the recording in the + customer's own storage (no SAS) that the customer downloads with their own credentials. The + recording is built once from the per-turn segments after persistence finalization succeeds. + While the conversation is ``in_progress``, this route returns retriable ``409 Conflict`` with + ``error.code = recording_not_ready`` and a ``Retry-After`` header when retry guidance is + available. When the conversation is ``failed``, it returns terminal ``409 Conflict`` with + ``error.code = recording_unavailable``. For a ``completed`` conversation, metadata is available + subject to the existing BYOS behavior. Requires the conversation to have persisted audio + (``store = true``); otherwise returns ``404``. - :param name: The name of the skill. If the skill does not exist, it will be created. 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 inline_content: Inline skill content for simple skills without file uploads. - Foundry-specific extension. Default value is None. - :paramtype inline_content: ~azure.ai.projects.models.SkillInlineContent - :keyword default: Whether to set this version as the default. Default value is None. - :paramtype default: bool - :return: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation whose merged recording metadata is + retrieved. Required. + :type conversation_id: str + :return: VoiceRecording. The VoiceRecording is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceRecording :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 create( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillVersion: - """Create a new version of a skill. + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - Creates a new version of a skill. If the skill does not exist, it will be created. + cls: ClsType[_models.VoiceRecording] = kwargs.pop("cls", None) - :param name: The name of the skill. If the skill 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: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ + _request = build_beta_voice_agents_conversations_get_audio_request( + agent_name=agent_name, + conversation_id=conversation_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) - @overload - def create( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillVersion: - """Create a new version of a skill. + _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 + ) - Creates a new version of a skill. If the skill does not exist, it will be created. + response = pipeline_response.http_response - :param name: The name of the skill. If the skill 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: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ + 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.VoiceRecording, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace - def create( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - inline_content: Optional[_models.SkillInlineContent] = None, - default: Optional[bool] = None, - **kwargs: Any - ) -> _models.SkillVersion: - """Create a new version of a skill. + def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> Iterator[bytes]: + """Stream a voice agent conversation's merged recording. - Creates a new version of a skill. If the skill does not exist, it will be created. + Streams the whole-call merged stereo recording as a WAV (``audio/wav``) byte stream through the + service (no SAS URL). This route serves Foundry-managed storage only. For + bring-your-own-storage (BYOS) recordings the bytes are not proxied — the caller must download + directly from customer storage using the ``blob_uri`` returned by the metadata route — so this + route returns ``409 Conflict`` for BYOS recordings. While the conversation is ``in_progress``, + this route returns retriable ``409 Conflict`` with ``error.code = recording_not_ready`` and a + ``Retry-After`` header when retry guidance is available. When the conversation is ``failed``, + it returns terminal ``409 Conflict`` with ``error.code = recording_unavailable``. For a + ``completed`` conversation, content is available subject to the existing BYOS behavior. A + conversation without persisted audio (``store = false``) returns ``404``. - :param name: The name of the skill. If the skill 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 inline_content: Inline skill content for simple skills without file uploads. - Foundry-specific extension. Default value is None. - :paramtype inline_content: ~azure.ai.projects.models.SkillInlineContent - :keyword default: Whether to set this version as the default. Default value is None. - :paramtype default: bool - :return: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param conversation_id: The id of the conversation whose merged recording is streamed. + Required. + :type conversation_id: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21579,27 +23880,15 @@ 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.SkillVersion] = kwargs.pop("cls", None) - - if body is _Unset: - body = {"default": default, "inline_content": inline_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 + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_skills_create_request( - name=name, - content_type=content_type, + _request = build_beta_voice_agents_conversations_download_audio_request( + agent_name=agent_name, + conversation_id=conversation_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -21609,7 +23898,7 @@ def create( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -21629,63 +23918,144 @@ def create( ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SkillVersion, response.json()) + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @overload - def create_from_files( - self, name: str, content: _models.CreateSkillVersionFromFilesBody, **kwargs: Any - ) -> _models.SkillVersion: - """Create a skill version from uploaded files. - Creates a new version of a skill from uploaded files via multipart form data. +class BetaVoiceAgentsLiveConversationsOperations: # pylint: disable=docstring-missing-param,name-too-long + """ + .. warning:: + **DO NOT** instantiate this class directly. - :param name: The name of the skill. Required. - :type name: str - :param content: The multipart request content. Required. - :type content: ~azure.ai.projects.models.CreateSkillVersionFromFilesBody - :return: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`live_conversations` attribute. + """ - @overload - def create_from_files(self, name: str, content: JSON, **kwargs: Any) -> _models.SkillVersion: - """Create a skill version from uploaded files. + 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") - Creates a new version of a skill from uploaded files via multipart form data. + @distributed_trace + def list( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.VoiceAgentLiveConversation"]: + """List Live voice agent conversations. - :param name: The name of the skill. Required. - :type name: str - :param content: The multipart request content. Required. - :type content: JSON - :return: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion + Lists stored Live conversations for this agent, including sessions stored via an override. + + :param agent_name: The name of the Live voice 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 VoiceAgentLiveConversation + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.VoiceAgentLiveConversation] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.VoiceAgentLiveConversation]] = 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_voice_agents_live_conversations_list_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.VoiceAgentLiveConversation], + 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 create_from_files( - self, name: str, content: Union[_models.CreateSkillVersionFromFilesBody, JSON], **kwargs: Any - ) -> _models.SkillVersion: - """Create a skill version from uploaded files. + def get(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceAgentLiveConversation: + """Get a Live voice agent conversation. - Creates a new version of a skill from uploaded files via multipart form data. + Gets a stored Live conversation; fetch items separately. Returns 404 if absent or not stored. - :param name: The name of the skill. Required. - :type name: str - :param content: The multipart request content. Is either a CreateSkillVersionFromFilesBody type - or a JSON type. Required. - :type content: ~azure.ai.projects.models.CreateSkillVersionFromFilesBody or JSON - :return: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :return: VoiceAgentLiveConversation. The VoiceAgentLiveConversation is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAgentLiveConversation :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21699,17 +24069,12 @@ def create_from_files( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillVersion] = kwargs.pop("cls", None) - - _body = content.as_dict() if isinstance(content, _Model) else content - _file_fields: list[str] = ["files"] - _data_fields: list[str] = ["default"] - _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + cls: ClsType[_models.VoiceAgentLiveConversation] = kwargs.pop("cls", None) - _request = build_beta_skills_create_from_files_request( - name=name, + _request = build_beta_voice_agents_live_conversations_get_request( + agent_name=agent_name, + conversation_id=conversation_id, api_version=self._config.api_version, - files=_files, headers=_headers, params=_params, ) @@ -21742,7 +24107,7 @@ def create_from_files( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillVersion, response.json()) + deserialized = _deserialize(_models.VoiceAgentLiveConversation, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -21750,21 +24115,86 @@ def create_from_files( return deserialized # type: ignore @distributed_trace - def list_versions( + def delete( # pylint: disable=inconsistent-return-statements + self, agent_name: str, conversation_id: str, **kwargs: Any + ) -> None: + """Delete a Live voice agent conversation. + + Deletes the stored conversation and its items/audio, without closing the Live session. + + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_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_voice_agents_live_conversations_delete_request( + agent_name=agent_name, + conversation_id=conversation_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 + + @distributed_trace + def list_items( self, - name: str, + agent_name: str, + conversation_id: str, *, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.SkillVersion"]: - """List skill versions. + ) -> ItemPaged["_models.VoiceAgentLiveConversationItem"]: + """List items in a Live voice agent conversation. - Returns the available versions for the specified skill. + Lists stored speech and delegation items in order; cursors use item IDs. Returns 404 if the + conversation is absent or not stored. - :param name: The name of the skill to list versions for. Required. - :type name: str + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_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. @@ -21779,14 +24209,14 @@ def list_versions( 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 SkillVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillVersion] + :return: An iterator like instance of VoiceAgentLiveConversationItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.VoiceAgentLiveConversationItem] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.SkillVersion]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.VoiceAgentLiveConversationItem]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -21798,8 +24228,9 @@ def list_versions( def prepare_request(_continuation_token=None): - _request = build_beta_skills_list_versions_request( - name=name, + _request = build_beta_voice_agents_live_conversations_list_items_request( + agent_name=agent_name, + conversation_id=conversation_id, limit=limit, order=order, after=_continuation_token, @@ -21817,7 +24248,7 @@ def prepare_request(_continuation_token=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.SkillVersion], + List[_models.VoiceAgentLiveConversationItem], deserialized.get("data", []), ) if cls: @@ -21846,17 +24277,23 @@ def get_next(_continuation_token=None): return ItemPaged(get_next, extract_data) @distributed_trace - def get_version(self, name: str, version: str, **kwargs: Any) -> _models.SkillVersion: - """Retrieve a specific version of a skill. + def get_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.VoiceAgentLiveConversationItem: + """Get a Live voice agent conversation item. - Retrieves the specified version of a skill by name and version identifier. + Gets a stored item by ID. Returns 404 if the item or conversation is absent. - :param name: The name of the skill. Required. - :type name: str - :param version: The version identifier to retrieve. Required. - :type version: str - :return: SkillVersion. The SkillVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillVersion + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :param item_id: The id returned on the persisted item. Required. + :type item_id: str + :return: VoiceAgentLiveConversationItem. The VoiceAgentLiveConversationItem is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAgentLiveConversationItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21870,11 +24307,12 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.SkillVe _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.VoiceAgentLiveConversationItem] = kwargs.pop("cls", None) - _request = build_beta_skills_get_version_request( - name=name, - version=version, + _request = build_beta_voice_agents_live_conversations_get_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -21908,7 +24346,7 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.SkillVe if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillVersion, response.json()) + deserialized = _deserialize(_models.VoiceAgentLiveConversationItem, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -21916,15 +24354,23 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.SkillVe return deserialized # type: ignore @distributed_trace - def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: - """Download the zip content for the default version of a skill. + def get_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> _models.VoiceAudioItem: + """Get a Live conversation item's audio metadata. - Downloads the zip content for the default version of a skill. + Gets captured speech-audio metadata. BYOS uses unsigned blob_uri. Returns 404 for missing + audio, conversations not stored, or delegation items. - :param name: The name of the skill. Required. - :type name: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :param item_id: The id returned on the persisted item. Required. + :type item_id: str + :return: VoiceAudioItem. The VoiceAudioItem is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceAudioItem :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -21938,10 +24384,12 @@ 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.VoiceAudioItem] = kwargs.pop("cls", None) - _request = build_beta_skills_download_request( - name=name, + _request = build_beta_voice_agents_live_conversations_get_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -21952,7 +24400,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 ) @@ -21972,26 +24420,32 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.VoiceAudioItem, 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 download_version(self, name: str, version: str, **kwargs: Any) -> Iterator[bytes]: - """Download the zip content for a specific version of a skill. + def download_audio_item( + self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any + ) -> Iterator[bytes]: + """Stream a Live conversation item's audio. - Downloads the zip content for a specific version of a skill. + Streams captured speech as WAV. BYOS returns 409; use blob_uri. Returns 404 for missing audio, + conversations not stored, or delegation items. - :param name: The name of the skill. Required. - :type name: str - :param version: The version to download content for. Required. - :type version: str + :param agent_name: The name of the Live voice agent. Required. + :type agent_name: str + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. + :type conversation_id: str + :param item_id: The id returned on the persisted item. Required. + :type item_id: str :return: Iterator[bytes] :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: @@ -22009,9 +24463,10 @@ def download_version(self, name: str, version: str, **kwargs: Any) -> Iterator[b cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_skills_download_version_request( - name=name, - version=version, + _request = build_beta_voice_agents_live_conversations_download_audio_item_request( + agent_name=agent_name, + conversation_id=conversation_id, + item_id=item_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -22038,220 +24493,35 @@ def download_version(self, name: str, version: str, **kwargs: Any) -> Iterator[b 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["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def delete_version(self, name: str, version: str, **kwargs: Any) -> _models.DeleteSkillVersionResult: - """Delete a specific version of a skill. - - Removes the specified version of a skill. - - :param name: The name of the skill. Required. - :type name: str - :param version: The version identifier to delete. Required. - :type version: str - :return: DeleteSkillVersionResult. The DeleteSkillVersionResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillVersionResult - :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.DeleteSkillVersionResult] = kwargs.pop("cls", None) - - _request = build_beta_skills_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) - - _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.DeleteSkillVersionResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - -class BetaVoiceAgentsConversationsOperations: # pylint: disable=docstring-missing-param - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`conversations` 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( - self, - agent_name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.VoiceConversation"]: - """List voice agent conversations. - - Returns the conversations persisted for the specified voice agent endpoint. Conversations are - present when the session's effective ``store`` setting is ``true``, whether inherited from the - agent definition or enabled by the WebSocket session override. - - :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 VoiceConversation - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.VoiceConversation] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.VoiceConversation]] = 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_voice_agents_conversations_list_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.VoiceConversation], - deserialized.get("data", []), + response, ) - 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) + raise HttpResponseError(response=response, model=error) - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - 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) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore - return ItemPaged(get_next, extract_data) + return deserialized # type: ignore @distributed_trace - def get(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceConversation: - """Get a voice agent conversation. + def get_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceRecording: + """Get a Live conversation's merged recording metadata. - Retrieves a single conversation recorded for the specified voice agent endpoint by its id. - Returns ``404`` when the conversation was not persisted (``store = false``) or does not exist. + Gets merged stereo recording metadata (user left, assistant right). BYOS uses unsigned + blob_uri. Returns 404 for no audio, or 409 recording_not_ready/recording_unavailable for + pending/failed finalization; pending responses may include Retry-After. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param conversation_id: The id of the conversation to retrieve. Required. + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. :type conversation_id: str - :return: VoiceConversation. The VoiceConversation is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.VoiceConversation + :return: VoiceRecording. The VoiceRecording is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.VoiceRecording :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -22265,9 +24535,9 @@ def get(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.V _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.VoiceConversation] = kwargs.pop("cls", None) + cls: ClsType[_models.VoiceRecording] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_conversations_get_request( + _request = build_beta_voice_agents_live_conversations_get_audio_request( agent_name=agent_name, conversation_id=conversation_id, api_version=self._config.api_version, @@ -22303,7 +24573,7 @@ def get(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.V if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.VoiceConversation, response.json()) + deserialized = _deserialize(_models.VoiceRecording, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -22311,20 +24581,19 @@ def get(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.V return deserialized # type: ignore @distributed_trace - def delete( # pylint: disable=inconsistent-return-statements - self, agent_name: str, conversation_id: str, **kwargs: Any - ) -> None: - """Delete a voice agent conversation. + def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> Iterator[bytes]: + """Stream a Live conversation's merged recording. - Deletes a conversation and all of its stored data — responses, items, and any audio (cascade). - This is the customer's explicit data-deletion control for voice conversations. + Streams the merged stereo WAV. BYOS returns 409; use blob_uri. Returns 404 for no audio, or 409 + recording_not_ready/recording_unavailable for pending/failed finalization. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the Live voice agent. Required. :type agent_name: str - :param conversation_id: The id of the conversation to delete. Required. + :param conversation_id: The Foundry conversation ID returned in + session.started.conversation_id. Required. :type conversation_id: str - :return: None - :rtype: None + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -22338,9 +24607,9 @@ def delete( # 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_voice_agents_conversations_delete_request( + _request = build_beta_voice_agents_live_conversations_download_audio_request( agent_name=agent_name, conversation_id=conversation_id, api_version=self._config.api_version, @@ -22352,14 +24621,20 @@ def delete( # 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, @@ -22367,130 +24642,114 @@ def delete( # 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 - @distributed_trace - def list_responses( + return deserialized # type: ignore + + +class BetaVoiceAgentsTelephonyOperations: # pylint: disable=docstring-missing-param + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`telephony` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + def create_binding( self, agent_name: str, - conversation_id: str, + binding: _models.TelephonyBinding, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + content_type: str = "application/json", **kwargs: Any - ) -> ItemPaged["_models.VoiceResponse"]: - """List responses in a voice agent conversation. + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - Returns a paged collection of the responses (model inference turns) recorded for the specified - conversation. The per-response ``output`` projection may be omitted here; use the - response-items route for the canonical paged output. Returns ``404`` when the conversation was - not persisted (``store = false``). + Creates a telephony binding for the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param conversation_id: The id of the conversation whose responses are listed. Required. - :type conversation_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 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 VoiceResponse - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.VoiceResponse] + :param binding: The provider-specific binding to create. Required. + :type binding: ~azure.ai.projects.models.TelephonyBinding + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.VoiceResponse]] = 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_voice_agents_conversations_list_responses_request( - agent_name=agent_name, - conversation_id=conversation_id, - 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.VoiceResponse], - 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) + @overload + def create_binding( + self, agent_name: str, binding: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + Creates a telephony binding for the voice agent named in the path. - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + :param agent_name: The name of the voice agent that owns the binding. Required. + :type agent_name: str + :param binding: The provider-specific binding to create. Required. + :type binding: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding + :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 + def create_binding( + self, agent_name: str, binding: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - return pipeline_response + Creates a telephony binding for the voice agent named in the path. - return ItemPaged(get_next, extract_data) + :param agent_name: The name of the voice agent that owns the binding. Required. + :type agent_name: str + :param binding: The provider-specific binding to create. Required. + :type binding: 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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def get_response( - self, agent_name: str, conversation_id: str, response_id: str, **kwargs: Any - ) -> _models.VoiceResponse: - """Get a voice agent conversation response. + def create_binding( + self, agent_name: str, binding: Union[_models.TelephonyBinding, JSON, IO[bytes]], **kwargs: Any + ) -> _models.TelephonyBinding: + """Create an agent telephony binding. - Retrieves a single response from the specified conversation by its id, including its ``output`` - items, ``usage``, and status. Returns ``404`` when the conversation or response was not - persisted (``store = false``). + Creates a telephony binding for the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the response. Required. - :type conversation_id: str - :param response_id: The id of the response to retrieve. Required. - :type response_id: str - :return: VoiceResponse. The VoiceResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.VoiceResponse + :param binding: The provider-specific binding to create. Is one of the following types: + TelephonyBinding, JSON, IO[bytes] Required. + :type binding: ~azure.ai.projects.models.TelephonyBinding or JSON or IO[bytes] + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -22501,16 +24760,24 @@ def get_response( } 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.VoiceResponse] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_conversations_get_response_request( + content_type = content_type or "application/json" + _content = None + if isinstance(binding, (IOBase, bytes)): + _content = binding + else: + _content = json.dumps(binding, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_voice_agents_telephony_create_binding_request( agent_name=agent_name, - conversation_id=conversation_id, - response_id=response_id, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -22527,7 +24794,7 @@ def get_response( 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 @@ -22540,41 +24807,39 @@ def get_response( ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.VoiceResponse, response.json()) + deserialized = _deserialize(_models.TelephonyBinding, 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_response_items( + def list_bindings( self, agent_name: str, - conversation_id: str, - response_id: str, *, + provider: Optional[Union[str, _models.TelephonyProvider]] = None, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.RealtimeConversationItem"]: - """List items produced by a voice agent conversation response. + ) -> ItemPaged["_models.TelephonyBindingListItem"]: + """List agent telephony bindings. - Returns a paged collection of the output items produced by a specific response (the response's - output projection). For the complete ordered conversation history — including user input and - client-created tool outputs — use the conversation items route instead. Returns ``404`` when - the conversation or response was not persisted (``store = false``). + Returns the telephony bindings owned by the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent whose bindings are listed. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the response. Required. - :type conversation_id: str - :param response_id: The id of the response whose output items are listed. Required. - :type response_id: str + :keyword provider: Filters bindings by provider. Known values are: "teams_phone_extensibility", + "twilio", and "sip". Default value is None. + :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider :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. @@ -22589,14 +24854,14 @@ def list_response_items( 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 RealtimeConversationItem - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RealtimeConversationItem] + :return: An iterator like instance of TelephonyBindingListItem + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyBindingListItem] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.RealtimeConversationItem]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.TelephonyBindingListItem]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -22608,10 +24873,9 @@ def list_response_items( def prepare_request(_continuation_token=None): - _request = build_beta_voice_agents_conversations_list_response_items_request( + _request = build_beta_voice_agents_telephony_list_bindings_request( agent_name=agent_name, - conversation_id=conversation_id, - response_id=response_id, + provider=provider, limit=limit, order=order, after=_continuation_token, @@ -22629,7 +24893,7 @@ def prepare_request(_continuation_token=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.RealtimeConversationItem], + List[_models.TelephonyBindingListItem], deserialized.get("data", []), ) if cls: @@ -22658,49 +24922,19 @@ def get_next(_continuation_token=None): return ItemPaged(get_next, extract_data) @distributed_trace - def list_items( - self, - agent_name: str, - conversation_id: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.RealtimeConversationItem"]: - """List items in a voice agent conversation. + def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _models.TelephonyBinding: + """Get an agent telephony binding. - Returns a paged collection of items — the complete ordered conversation history, including user - input, assistant output, and client-created tool outputs (transcripts + tool events). Returns - ``404`` when the conversation was not persisted (``store = false``). + Retrieves a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param conversation_id: The id of the conversation whose items are listed. Required. - :type conversation_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 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 RealtimeConversationItem - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RealtimeConversationItem] + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.RealtimeConversationItem]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -22709,77 +24943,187 @@ def list_items( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _request = build_beta_voice_agents_conversations_list_items_request( - agent_name=agent_name, - conversation_id=conversation_id, - 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 + cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.RealtimeConversationItem], - 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) + _request = build_beta_voice_agents_telephony_get_binding_request( + agent_name=agent_name, + binding_id=binding_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 get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + _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 + ) - _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, ) - 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["ETag"] = self._deserialize("str", response.headers.get("ETag")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyBinding, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @overload + def update_binding( + self, + agent_name: str, + binding_id: str, + body: _models.UpdateTelephonyBindingRequest, + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. + + Updates a telephony binding owned by the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the binding. Required. + :type agent_name: str + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Required. + :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update_binding( + self, + agent_name: str, + binding_id: str, + body: JSON, + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. + + Updates a telephony binding owned by the voice agent named in the path. + + :param agent_name: The name of the voice agent that owns the binding. Required. + :type agent_name: str + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Required. + :type body: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update_binding( + self, + agent_name: str, + binding_id: str, + body: IO[bytes], + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. - return pipeline_response + Updates a telephony binding owned by the voice agent named in the path. - return ItemPaged(get_next, extract_data) + :param agent_name: The name of the voice agent that owns the binding. Required. + :type agent_name: str + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Required. + :type body: IO[bytes] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def get_item( - self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any - ) -> _models.RealtimeConversationItem: - """Get a voice agent conversation item. + def update_binding( + self, + agent_name: str, + binding_id: str, + body: Union[_models.UpdateTelephonyBindingRequest, JSON, IO[bytes]], + *, + etag: str, + match_condition: MatchConditions, + **kwargs: Any + ) -> _models.TelephonyBinding: + """Update an agent telephony binding. - Retrieves a single item from the specified conversation by its id, including its transcript. An - ``input_audio``/``output_audio`` content part indicates that audio is available for the item; - the canonical per-item audio metadata is the ``/items/{item_id}/audio`` resource, and the bytes - are streamed by ``/items/{item_id}/audio/content``. Returns ``404`` when the conversation or - item was not persisted (``store = false``). + Updates a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the item. Required. - :type conversation_id: str - :param item_id: The id of the conversation item to retrieve. Required. - :type item_id: str - :return: RealtimeConversationItem. The RealtimeConversationItem is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.RealtimeConversationItem + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :param body: The binding properties to update. Is one of the following types: + UpdateTelephonyBindingRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest or JSON or IO[bytes] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyBinding :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -22788,18 +25132,35 @@ def get_item( 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError 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.RealtimeConversationItem] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TelephonyBinding] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_conversations_get_item_request( + 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_voice_agents_telephony_update_binding_request( agent_name=agent_name, - conversation_id=conversation_id, - item_id=item_id, + binding_id=binding_id, + etag=etag, + match_condition=match_condition, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -22829,38 +25190,37 @@ def get_item( ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RealtimeConversationItem, response.json()) + deserialized = _deserialize(_models.TelephonyBinding, 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_audio_item( - self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any - ) -> _models.VoiceAudioItem: - """Get a voice agent conversation item's audio metadata. + def delete_binding( # pylint: disable=inconsistent-return-statements + self, agent_name: str, binding_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any + ) -> None: + """Delete an agent telephony binding. - Returns metadata for a single conversation item's audio segment, including the common playback - facts (role, format/codec, sample rate, channels, offset, duration) for both Foundry-managed - and bring-your-own-storage (BYOS) recordings; for BYOS the response additionally includes - ``blob_uri``, the URI of the recording in the customer's own storage (no SAS) that the customer - downloads with their own credentials. Requires the conversation to have persisted audio - (``store = true``); returns ``404`` when the conversation, item, or its audio was not - persisted. + Deletes a telephony binding owned by the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the binding. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the item. Required. - :type conversation_id: str - :param item_id: The id of the conversation item whose audio metadata is retrieved. Required. - :type item_id: str - :return: VoiceAudioItem. The VoiceAudioItem is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.VoiceAudioItem + :param binding_id: The service-generated binding identifier. Required. + :type binding_id: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -22869,17 +25229,24 @@ def get_audio_item( 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.VoiceAudioItem] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_conversations_get_audio_item_request( + _request = build_beta_voice_agents_telephony_delete_binding_request( agent_name=agent_name, - conversation_id=conversation_id, - item_id=item_id, + binding_id=binding_id, + etag=etag, + match_condition=match_condition, api_version=self._config.api_version, headers=_headers, params=_params, @@ -22889,20 +25256,14 @@ def get_audio_item( } _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, @@ -22910,39 +25271,64 @@ def get_audio_item( ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.VoiceAudioItem, response.json()) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def download_audio_item( - self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any - ) -> Iterator[bytes]: - """Stream a voice agent conversation item's audio. + def list_calls( + self, + agent_name: str, + *, + provider: Optional[Union[str, _models.TelephonyProvider]] = None, + status: Optional[Union[str, _models.TelephonyCallStatus]] = None, + started_after_time: Optional[datetime.datetime] = None, + started_before_time: Optional[datetime.datetime] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.TelephonyCallSummary"]: + """List agent telephony calls. - Streams a single conversation item's audio as a WAV (``audio/wav``) byte stream through the - service (no SAS URL). This route serves Foundry-managed storage only. For - bring-your-own-storage (BYOS) recordings the bytes are not proxied — the caller must download - directly from customer storage using the ``blob_uri`` returned by the item's ``/audio`` - metadata route — so this route returns ``409 Conflict`` for BYOS recordings. Returns ``404`` - when the conversation, item, or its audio was not persisted (``store = false``). + Returns the durable inbound call history for the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent whose calls are listed. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the item. Required. - :type conversation_id: str - :param item_id: The id of the conversation item whose audio is streamed. Required. - :type item_id: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :keyword provider: Filters calls by provider. Known values are: "teams_phone_extensibility", + "twilio", and "sip". Default value is None. + :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider + :keyword status: Filters calls by lifecycle status. Known values are: "in_progress", "success", + and "failed". Default value is None. + :paramtype status: str or ~azure.ai.projects.models.TelephonyCallStatus + :keyword started_after_time: Includes calls that started at or after this Unix timestamp in + seconds. Default value is None. + :paramtype started_after_time: ~datetime.datetime + :keyword started_before_time: Includes calls that started at or before this Unix timestamp in + seconds. Default value is None. + :paramtype started_before_time: ~datetime.datetime + :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 TelephonyCallSummary + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyCallSummary] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCallSummary]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -22951,76 +25337,71 @@ def download_audio_item( } 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) + def prepare_request(_continuation_token=None): - _request = build_beta_voice_agents_conversations_download_audio_item_request( - agent_name=agent_name, - conversation_id=conversation_id, - item_id=item_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) + _request = build_beta_voice_agents_telephony_list_calls_request( + agent_name=agent_name, + provider=provider, + status=status, + started_after_time=started_after_time, + started_before_time=started_before_time, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.TelephonyCallSummary], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) - response = pipeline_response.http_response + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + 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) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - 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 get_generated_audio_item( - self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any - ) -> _models.VoiceGeneratedAudioItem: - """Get a voice agent conversation item's generated audio metadata. + def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: + """Get an agent telephony call. - Returns metadata for a conversation item's generated audio. This subordinate artifact is - separate from the canonical heard-audio segment and exists only when playback was interrupted - and the service rendered more audio than the listener heard, including when the response ends - as cancelled. Returns ``404`` when the conversation or item was not persisted, or when no - generated audio exists beyond the heard segment. + Retrieves a durable inbound call record owned by the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the call record. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the item. Required. - :type conversation_id: str - :param item_id: The id of the conversation item whose generated audio metadata is retrieved. - Required. - :type item_id: str - :return: VoiceGeneratedAudioItem. The VoiceGeneratedAudioItem is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.VoiceGeneratedAudioItem + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -23034,12 +25415,11 @@ def get_generated_audio_item( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.VoiceGeneratedAudioItem] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_conversations_get_generated_audio_item_request( + _request = build_beta_voice_agents_telephony_get_call_request( agent_name=agent_name, - conversation_id=conversation_id, - item_id=item_id, + call_id=call_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -23073,118 +25453,103 @@ def get_generated_audio_item( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.VoiceGeneratedAudioItem, response.json()) + deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def download_generated_audio_item( - self, agent_name: str, conversation_id: str, item_id: str, **kwargs: Any - ) -> Iterator[bytes]: - """Stream a voice agent conversation item's generated audio. + @overload + def transfer_call( + self, agent_name: str, call_id: str, *, target: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. - Streams a conversation item's generated audio as a WAV (``audio/wav``) byte stream through the - service. This subordinate artifact exists only when playback was interrupted and the service - rendered more audio than the listener heard, including when the response ends as cancelled. - This route serves Foundry-managed storage only. For bring-your-own-storage (BYOS) recordings - the bytes are not proxied, so this route returns ``409 Conflict``. Returns ``404`` when the - conversation or item was not persisted, or when no generated audio exists beyond the heard - segment. + Transfers an active inbound call to a configured target for the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the active call. Required. :type agent_name: str - :param conversation_id: The id of the conversation that contains the item. Required. - :type conversation_id: str - :param item_id: The id of the conversation item whose generated audio is streamed. Required. - :type item_id: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :keyword target: The name of a transfer target configured for the voice agent. Required. + :paramtype target: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord :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_voice_agents_conversations_download_generated_audio_item_request( - agent_name=agent_name, - conversation_id=conversation_id, - item_id=item_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", True) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + @overload + def transfer_call( + self, agent_name: str, call_id: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. - 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) + Transfers an active inbound call to a configured target for the voice agent named in the path. - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :raises ~azure.core.exceptions.HttpResponseError: + """ - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + @overload + def transfer_call( + self, agent_name: str, call_id: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + Transfers an active inbound call to a configured target for the voice agent named in the path. - return deserialized # type: ignore + :param agent_name: The name of the voice agent that owns the active call. Required. + :type agent_name: str + :param call_id: The service-generated call identifier. Required. + :type call_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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def get_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _models.VoiceRecording: - """Get a voice agent conversation's merged recording metadata. + def transfer_call( + self, + agent_name: str, + call_id: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + target: str = _Unset, + **kwargs: Any + ) -> _models.TelephonyCallRecord: + """Transfer an active agent telephony call. - Returns metadata for the whole-call merged stereo recording (user audio on the left channel, - agent audio on the right). The common metadata (format, sample rate, channels, channel layout, - duration) is returned for both Foundry-managed and bring-your-own-storage (BYOS) recordings; - for BYOS the response additionally includes ``blob_uri``, the URI of the recording in the - customer's own storage (no SAS) that the customer downloads with their own credentials. The - recording is built once from the per-turn segments after persistence finalization succeeds. - While the conversation is ``in_progress``, this route returns retriable ``409 Conflict`` with - ``error.code = recording_not_ready`` and a ``Retry-After`` header when retry guidance is - available. When the conversation is ``failed``, it returns terminal ``409 Conflict`` with - ``error.code = recording_unavailable``. For a ``completed`` conversation, metadata is available - subject to the existing BYOS behavior. Requires the conversation to have persisted audio - (``store = true``); otherwise returns ``404``. + Transfers an active inbound call to a configured target for the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the active call. Required. :type agent_name: str - :param conversation_id: The id of the conversation whose merged recording metadata is - retrieved. Required. - :type conversation_id: str - :return: VoiceRecording. The VoiceRecording is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.VoiceRecording + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword target: The name of a transfer target configured for the voice agent. Required. + :paramtype target: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -23195,15 +25560,30 @@ def get_audio(self, agent_name: str, conversation_id: 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.VoiceRecording] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) + + if body is _Unset: + if target is _Unset: + raise TypeError("missing required argument: target") + body = {"target": target} + 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_voice_agents_conversations_get_audio_request( + _request = build_beta_voice_agents_telephony_transfer_call_request( agent_name=agent_name, - conversation_id=conversation_id, + call_id=call_id, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -23236,7 +25616,7 @@ def get_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _mo if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.VoiceRecording, response.json()) + deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -23244,27 +25624,17 @@ def get_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> _mo return deserialized # type: ignore @distributed_trace - def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) -> Iterator[bytes]: - """Stream a voice agent conversation's merged recording. + def end_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: + """End an active agent telephony call. - Streams the whole-call merged stereo recording as a WAV (``audio/wav``) byte stream through the - service (no SAS URL). This route serves Foundry-managed storage only. For - bring-your-own-storage (BYOS) recordings the bytes are not proxied — the caller must download - directly from customer storage using the ``blob_uri`` returned by the metadata route — so this - route returns ``409 Conflict`` for BYOS recordings. While the conversation is ``in_progress``, - this route returns retriable ``409 Conflict`` with ``error.code = recording_not_ready`` and a - ``Retry-After`` header when retry guidance is available. When the conversation is ``failed``, - it returns terminal ``409 Conflict`` with ``error.code = recording_unavailable``. For a - ``completed`` conversation, content is available subject to the existing BYOS behavior. A - conversation without persisted audio (``store = false``) returns ``404``. + Ends an active inbound call owned by the voice agent named in the path. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the voice agent that owns the active call. Required. :type agent_name: str - :param conversation_id: The id of the conversation whose merged recording is streamed. - Required. - :type conversation_id: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param call_id: The service-generated call identifier. Required. + :type call_id: str + :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallRecord :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -23278,11 +25648,11 @@ def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) - _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_conversations_download_audio_request( + _request = build_beta_voice_agents_telephony_end_call_request( agent_name=agent_name, - conversation_id=conversation_id, + call_id=call_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -23293,7 +25663,7 @@ def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) - _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 ) @@ -23313,118 +25683,27 @@ def download_audio(self, agent_name: str, conversation_id: str, **kwargs: Any) - ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - -class BetaVoiceAgentsTelephonyOperations: # pylint: disable=docstring-missing-param - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`telephony` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - - @overload - def create_binding( - self, - agent_name: str, - telephony_binding: _models.CreateTelephonyBindingRequest, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. - - Creates a telephony binding for the voice agent named in the path. - - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Required. - :type telephony_binding: ~azure.ai.projects.models.CreateTelephonyBindingRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_binding( - self, agent_name: str, telephony_binding: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. - - Creates a telephony binding for the voice agent named in the path. - - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Required. - :type telephony_binding: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_binding( - self, agent_name: str, telephony_binding: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. - - Creates a telephony binding for the voice agent named in the path. - - :param agent_name: The name of the voice agent that owns the binding. Required. - :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Required. - :type telephony_binding: 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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace - def create_binding( - self, - agent_name: str, - telephony_binding: Union[_models.CreateTelephonyBindingRequest, JSON, IO[bytes]], - **kwargs: Any - ) -> _models.TelephonyBinding: - """Create an agent telephony binding. + def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models.TelephonyTransferTargets: + """Get agent telephony transfer targets. - Creates a telephony binding for the voice agent named in the path. + Returns all transfer targets configured for the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the voice agent whose transfer targets are retrieved. Required. :type agent_name: str - :param telephony_binding: The provider-specific binding to create. Is one of the following - types: CreateTelephonyBindingRequest, JSON, IO[bytes] Required. - :type telephony_binding: ~azure.ai.projects.models.CreateTelephonyBindingRequest or JSON or - IO[bytes] - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -23435,24 +25714,14 @@ def create_binding( } 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.TelephonyBinding] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(telephony_binding, (IOBase, bytes)): - _content = telephony_binding - else: - _content = json.dumps(telephony_binding, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.TelephonyTransferTargets] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_create_binding_request( + _request = build_beta_voice_agents_telephony_get_transfer_targets_request( agent_name=agent_name, - content_type=content_type, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -23469,7 +25738,7 @@ def create_binding( 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 @@ -23488,131 +25757,139 @@ def create_binding( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyBinding, response.json()) + deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @distributed_trace - def list_bindings( + @overload + def replace_transfer_targets( self, agent_name: str, *, - provider: Optional[Union[str, _models.TelephonyProvider]] = None, - status: Optional[Union[str, _models.TelephonyBindingStatus]] = None, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + transfer_targets: List[_models.TelephonyTransferTarget], + etag: str, + match_condition: MatchConditions, + content_type: str = "application/json", **kwargs: Any - ) -> ItemPaged["_models.TelephonyBindingListItem"]: - """List agent telephony bindings. + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. - Returns the telephony bindings owned by the voice agent named in the path. + Replaces all transfer targets configured for the voice agent named in the path. - :param agent_name: The name of the voice agent whose bindings are listed. Required. + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. :type agent_name: str - :keyword provider: Filters bindings by provider. Known values are: "teams_phone_extensibility" - and "twilio". Default value is None. - :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider - :keyword status: Filters bindings by lifecycle status. Known values are: "active" and - "suspended". Default value is None. - :paramtype status: str or ~azure.ai.projects.models.TelephonyBindingStatus - :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 TelephonyBindingListItem - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyBindingListItem] + :keyword transfer_targets: The complete set of destinations to which the voice agent may + transfer calls. An empty array clears all targets when replacing the configuration. Required. + :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.TelephonyBindingListItem]] = 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_voice_agents_telephony_list_bindings_request( - agent_name=agent_name, - provider=provider, - status=status, - 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.TelephonyBindingListItem], - 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) + @overload + def replace_transfer_targets( + self, + agent_name: str, + body: JSON, + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + Replaces all transfer targets configured for the voice agent named in the path. - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :type agent_name: str + :param body: Required. + :type body: JSON + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :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 + def replace_transfer_targets( + self, + agent_name: str, + body: IO[bytes], + *, + etag: str, + match_condition: MatchConditions, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. - return pipeline_response + Replaces all transfer targets configured for the voice agent named in the path. - return ItemPaged(get_next, extract_data) + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :type agent_name: str + :param body: Required. + :type body: IO[bytes] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _models.TelephonyBinding: - """Get an agent telephony binding. + def replace_transfer_targets( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + transfer_targets: List[_models.TelephonyTransferTarget] = _Unset, + etag: str, + match_condition: MatchConditions, + **kwargs: Any + ) -> _models.TelephonyTransferTargets: + """Replace agent telephony transfer targets. - Retrieves a telephony binding owned by the voice agent named in the path. + Replaces all transfer targets configured for the voice agent named in the path. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword transfer_targets: The complete set of destinations to which the voice agent may + transfer calls. An empty array clears all targets when replacing the configuration. Required. + :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyTransferTargets :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -23621,17 +25898,39 @@ def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _model 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError 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.TelephonyBinding] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TelephonyTransferTargets] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_get_binding_request( + if body is _Unset: + if transfer_targets is _Unset: + raise TypeError("missing required argument: transfer_targets") + body = {"transfer_targets": transfer_targets} + 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_voice_agents_telephony_replace_transfer_targets_request( agent_name=agent_name, - binding_id=binding_id, + etag=etag, + match_condition=match_condition, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -23667,7 +25966,7 @@ def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _model if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyBinding, response.json()) + deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -23675,135 +25974,113 @@ def get_binding(self, agent_name: str, binding_id: str, **kwargs: Any) -> _model return deserialized # type: ignore @overload - def update_binding( + def create_call_job( self, agent_name: str, - binding_id: str, - body: _models.UpdateTelephonyBindingRequest, + job: _models.TelephonyCallJobCreate, *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/merge-patch+json", + idempotency_key: str, + content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. - Updates a telephony binding owned by the voice agent named in the path. + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the voice agent that executes the call. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Required. - :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions + :param job: The direct outbound call to create. Required. + :type job: ~azure.ai.projects.models.TelephonyCallJobCreate + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_key: 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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update_binding( - self, - agent_name: str, - binding_id: str, - body: JSON, - *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + def create_call_job( + self, agent_name: str, job: JSON, *, idempotency_key: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. - Updates a telephony binding owned by the voice agent named in the path. + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the voice agent that executes the call. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Required. - :type body: JSON - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions + :param job: The direct outbound call to create. Required. + :type job: JSON + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_key: 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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update_binding( + def create_call_job( self, agent_name: str, - binding_id: str, - body: IO[bytes], + job: IO[bytes], *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/merge-patch+json", + idempotency_key: str, + content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. - Updates a telephony binding owned by the voice agent named in the path. + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the voice agent that executes the call. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Required. - :type body: IO[bytes] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions + :param job: The direct outbound call to create. Required. + :type job: IO[bytes] + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_key: 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: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update_binding( + def create_call_job( self, agent_name: str, - binding_id: str, - body: Union[_models.UpdateTelephonyBindingRequest, JSON, IO[bytes]], + job: Union[_models.TelephonyCallJobCreate, JSON, IO[bytes]], *, - etag: str, - match_condition: MatchConditions, + idempotency_key: str, **kwargs: Any - ) -> _models.TelephonyBinding: - """Update an agent telephony binding. + ) -> _models.TelephonyCallJob: + """Create an outbound telephony call job. - Updates a telephony binding owned by the voice agent named in the path. + Creates one durable outbound CallJob. Each attempt pins the Agent endpoint's execution version + for validation and its voice session. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The name of the voice agent that executes the call. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :param body: The binding properties to update. Is one of the following types: - UpdateTelephonyBindingRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.UpdateTelephonyBindingRequest or JSON or IO[bytes] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :return: TelephonyBinding. The TelephonyBinding is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyBinding + :param job: The direct outbound call to create. Is one of the following types: + TelephonyCallJobCreate, JSON, IO[bytes] Required. + :type job: ~azure.ai.projects.models.TelephonyCallJobCreate or JSON or IO[bytes] + :keyword idempotency_key: Customer retry key. Equivalent requests return the same job; retained + keys for deleted jobs return 409 call_job_deleted, never redial. Required. + :paramtype idempotency_key: str + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -23812,32 +26089,24 @@ def update_binding( 409: ResourceExistsError, 304: ResourceNotModifiedError, } - if match_condition == MatchConditions.IfNotModified: - error_map[412] = ResourceModifiedError - elif match_condition == MatchConditions.IfPresent: - error_map[412] = ResourceNotFoundError - elif match_condition == MatchConditions.IfMissing: - error_map[412] = ResourceExistsError 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.TelephonyBinding] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) - content_type = content_type or "application/merge-patch+json" + content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(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_voice_agents_telephony_update_binding_request( + _request = build_beta_voice_agents_telephony_create_call_job_request( agent_name=agent_name, - binding_id=binding_id, - etag=etag, - match_condition=match_condition, + idempotency_key=idempotency_key, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -23857,7 +26126,7 @@ def update_binding( 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 @@ -23872,11 +26141,13 @@ def update_binding( response_headers = {} response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Retry-After"] = self._deserialize("duration-seconds-int", response.headers.get("Retry-After")) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyBinding, response.json()) + deserialized = _deserialize(_models.TelephonyCallJob, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -23884,21 +26155,129 @@ def update_binding( return deserialized # type: ignore @distributed_trace - def delete_binding( # pylint: disable=inconsistent-return-statements - self, agent_name: str, binding_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any + def list_call_jobs( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.TelephonyCallJobStatus]] = None, + campaign_name: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.TelephonyCallJob"]: + """List outbound telephony call jobs. + + Lists current direct/Campaign jobs, excluding deleted or superseded rounds. Pages are live. + Campaign cursors survive boundary deletion/cancel, not replacement/name reuse (400 + invalid_cursor). + + :param agent_name: The owning voice agent. Authorization is applied before pagination. + 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 + :keyword status: Optional lifecycle filter. Known values are: "accepted", + "waiting_for_schedule", "queued", "dispatching", "in_progress", "waiting_for_retry", + "cancellation_requested", "completed", "blocked", "expired", "failed", and "cancelled". Default + value is None. + :paramtype status: str or ~azure.ai.projects.models.TelephonyCallJobStatus + :keyword campaign_name: Current Campaign round: 404 if absent, empty while deleting. Omit for + direct and Campaign jobs. Replacement/name reuse invalidates cursors. Default value is None. + :paramtype campaign_name: str + :return: An iterator like instance of TelephonyCallJob + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyCallJob] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCallJob]] = 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_voice_agents_telephony_list_call_jobs_request( + agent_name=agent_name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + status=status, + campaign_name=campaign_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.TelephonyCallJob], + 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 delete_call_job( # pylint: disable=inconsistent-return-statements + self, agent_name: str, call_job_id: str, **kwargs: Any ) -> None: - """Delete an agent telephony binding. + """Delete an outbound telephony call job. - Deletes a telephony binding owned by the voice agent named in the path. + Deletes a terminal, reconciled job (otherwise 409), without cancelling calls or removing + Campaign outcomes/call history. Later GET returns 404; repeated DELETE returns 204. - :param agent_name: The name of the voice agent that owns the binding. Required. + :param agent_name: The owning voice agent. Required. :type agent_name: str - :param binding_id: The service-generated binding identifier. Required. - :type binding_id: str - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions + :param call_job_id: The call-job identifier. Required. + :type call_job_id: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -23909,12 +26288,6 @@ def delete_binding( # pylint: disable=inconsistent-return-statements 409: ResourceExistsError, 304: ResourceNotModifiedError, } - if match_condition == MatchConditions.IfNotModified: - error_map[412] = ResourceModifiedError - elif match_condition == MatchConditions.IfPresent: - error_map[412] = ResourceNotFoundError - elif match_condition == MatchConditions.IfMissing: - error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} @@ -23922,11 +26295,9 @@ def delete_binding( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_delete_binding_request( + _request = build_beta_voice_agents_telephony_delete_call_job_request( agent_name=agent_name, - binding_id=binding_id, - etag=etag, - match_condition=match_condition, + call_job_id=call_job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -23955,60 +26326,19 @@ def delete_binding( # pylint: disable=inconsistent-return-statements return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def list_calls( - self, - agent_name: str, - *, - provider: Optional[Union[str, _models.TelephonyProvider]] = None, - status: Optional[Union[str, _models.TelephonyCallStatus]] = None, - started_after_time: Optional[datetime.datetime] = None, - started_before_time: Optional[datetime.datetime] = None, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.TelephonyCallSummary"]: - """List agent telephony calls. + def get_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) -> _models.TelephonyCallJob: + """Get an outbound telephony call job. - Returns the durable inbound call history for the voice agent named in the path. + Retrieves a durable direct or campaign-created outbound call job. - :param agent_name: The name of the voice agent whose calls are listed. Required. + :param agent_name: The name of the voice agent that owns the call job. Required. :type agent_name: str - :keyword provider: Filters calls by provider. Known values are: "teams_phone_extensibility" and - "twilio". Default value is None. - :paramtype provider: str or ~azure.ai.projects.models.TelephonyProvider - :keyword status: Filters calls by lifecycle status. Known values are: "in_progress", "success", - and "failed". Default value is None. - :paramtype status: str or ~azure.ai.projects.models.TelephonyCallStatus - :keyword started_after_time: Includes calls that started at or after this Unix timestamp in - seconds. Default value is None. - :paramtype started_after_time: ~datetime.datetime - :keyword started_before_time: Includes calls that started at or before this Unix timestamp in - seconds. Default value is None. - :paramtype started_before_time: ~datetime.datetime - :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 TelephonyCallSummary - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyCallSummary] + :param call_job_id: The service-generated identifier of the call job to retrieve. Required. + :type call_job_id: str + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.TelephonyCallSummary]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -24017,71 +26347,76 @@ def list_calls( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _request = build_beta_voice_agents_telephony_list_calls_request( - agent_name=agent_name, - provider=provider, - status=status, - started_after_time=started_after_time, - started_before_time=started_before_time, - 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 + cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.TelephonyCallSummary], - 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) + _request = build_beta_voice_agents_telephony_get_call_job_request( + agent_name=agent_name, + call_job_id=call_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 + ) - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + 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) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - return pipeline_response + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.TelephonyCallJob, response.json()) - return ItemPaged(get_next, extract_data) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @distributed_trace - def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: - """Get an agent telephony call. + def cancel_call_job( + self, agent_name: str, call_job_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any + ) -> _models.TelephonyCallJob: + """Cancel an outbound telephony call job. - Retrieves a durable inbound call record owned by the voice agent named in the path. + Cancels future attempts using If-Match; completion may be asynchronous. New cancellation after + connection returns 409 and lets the active call finish. - :param agent_name: The name of the voice agent that owns the call record. Required. + :param agent_name: The name of the voice agent that owns the call job. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :param call_job_id: The service-generated identifier of the call job to cancel. Required. + :type call_job_id: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCallJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -24090,16 +26425,24 @@ def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.Tele 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_get_call_request( + _request = build_beta_voice_agents_telephony_cancel_call_job_request( agent_name=agent_name, - call_id=call_id, + call_job_id=call_job_id, + etag=etag, + match_condition=match_condition, api_version=self._config.api_version, headers=_headers, params=_params, @@ -24117,7 +26460,7 @@ def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.Tele response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [200, 202]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -24130,137 +26473,89 @@ def get_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.Tele ) raise HttpResponseError(response=response, model=error) + response_headers = {} + if response.status_code == 200: + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + + if response.status_code == 202: + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Retry-After"] = self._deserialize( + "duration-seconds-int", response.headers.get("Retry-After") + ) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) + deserialized = _deserialize(_models.TelephonyCallJob, 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 transfer_call( - self, agent_name: str, call_id: str, *, target: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. - - Transfers an active inbound call to a configured target for the voice agent named in the path. - - :param agent_name: The name of the voice agent that owns the active call. Required. - :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :keyword target: The name of a transfer target configured for the voice agent. Required. - :paramtype target: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def transfer_call( - self, agent_name: str, call_id: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. - - Transfers an active inbound call to a configured target for the voice agent named in the path. - - :param agent_name: The name of the voice agent that owns the active call. Required. - :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord - :raises ~azure.core.exceptions.HttpResponseError: - """ - @overload - def transfer_call( - self, agent_name: str, call_id: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. +class BetaVoiceAgentsCampaignsOperations: # pylint: disable=docstring-missing-param + """ + .. warning:: + **DO NOT** instantiate this class directly. - Transfers an active inbound call to a configured target for the voice agent named in the path. + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`campaigns` attribute. + """ - :param agent_name: The name of the voice agent that owns the active call. Required. - :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_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: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord - :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 transfer_call( + def _create_initial( self, agent_name: str, - call_id: str, - body: Union[JSON, IO[bytes]] = _Unset, + campaign_name: str, + campaign: Union[_models.TelephonyCampaign, JSON, IO[bytes]], *, - target: str = _Unset, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, **kwargs: Any - ) -> _models.TelephonyCallRecord: - """Transfer an active agent telephony call. - - Transfers an active inbound call to a configured target for the voice agent named in the path. - - :param agent_name: The name of the voice agent that owns the active call. Required. - :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword target: The name of a transfer target configured for the voice agent. Required. - :paramtype target: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord - :raises ~azure.core.exceptions.HttpResponseError: - """ + ) -> Iterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError 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.TelephonyCallRecord] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - if body is _Unset: - if target is _Unset: - raise TypeError("missing required argument: target") - body = {"target": target} - 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(campaign, (IOBase, bytes)): + _content = campaign else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(campaign, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_voice_agents_telephony_transfer_call_request( + _request = build_beta_voice_agents_campaigns_create_request( agent_name=agent_name, - call_id=call_id, + campaign_name=campaign_name, + operation_id=operation_id, + etag=etag, + match_condition=match_condition, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -24273,19 +26568,18 @@ def transfer_call( _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 ) 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 [200, 201]: + 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, @@ -24293,97 +26587,282 @@ def transfer_call( ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) + response_headers = {} + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: _models.TelephonyCampaign, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> LROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Required. + :type campaign: ~azure.ai.projects.models.TelephonyCampaign + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. 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 etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of LROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: JSON, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> LROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. - return deserialized # type: ignore + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Required. + :type campaign: JSON + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. 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 etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of LROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ - @distributed_trace - def end_call(self, agent_name: str, call_id: str, **kwargs: Any) -> _models.TelephonyCallRecord: - """End an active agent telephony call. + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> LROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. - Ends an active inbound call owned by the voice agent named in the path. + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. - :param agent_name: The name of the voice agent that owns the active call. Required. + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. :type agent_name: str - :param call_id: The service-generated call identifier. Required. - :type call_id: str - :return: TelephonyCallRecord. The TelephonyCallRecord is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallRecord + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Required. + :type campaign: IO[bytes] + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. 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 + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of LROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] :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 {} + @distributed_trace + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: Union[_models.TelephonyCampaign, JSON, IO[bytes]], + *, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any + ) -> LROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + Creates a Campaign or fully replaces failed preparation; no PATCH. All recipients must validate + and have CallJobs before dialing. Immediate calls may begin before the preparation poller + returns. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Name chosen by the caller; only a failed Campaign permits full + replacement. Required. + :type campaign_name: str + :param campaign: Complete connection, source, recipients/Dataset, schedule and retry + configuration. Omitted optional fields reset to defaults; Agent/name and response-only fields + cannot change. Is one of the following types: TelephonyCampaign, JSON, IO[bytes] Required. + :type campaign: ~azure.ai.projects.models.TelephonyCampaign or JSON or IO[bytes] + :keyword operation_id: Retry key: matching submitted inputs and original If-Match replay the + saved monitor before current-state checks. Conflicting reuse returns 409 operation_id_conflict; + retained creation keys after deletion return 409 campaign_deleted. Default value is None. + :paramtype operation_id: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Default value is + None. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Default value is None. + :paramtype match_condition: ~azure.core.MatchConditions + :return: An instance of LROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyCallRecord] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.TelephonyCampaign] = 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._create_initial( + agent_name=agent_name, + campaign_name=campaign_name, + campaign=campaign, + operation_id=operation_id, + etag=etag, + match_condition=match_condition, + 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["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + deserialized = _deserialize(_models.TelephonyCampaign, response.json()) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized - _request = build_beta_voice_agents_telephony_end_call_request( - agent_name=agent_name, - call_id=call_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, + if polling is True: + polling_method: PollingMethod = cast( + PollingMethod, LROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + elif polling is False: + polling_method = cast(PollingMethod, NoPolling()) else: - deserialized = _deserialize(_models.TelephonyCallRecord, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + polling_method = polling + if cont_token: + return LROPoller[_models.TelephonyCampaign].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return LROPoller[_models.TelephonyCampaign]( + self._client, raw_result, get_long_running_output, polling_method # type: ignore + ) @distributed_trace - def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models.TelephonyTransferTargets: - """Get agent telephony transfer targets. + def get( + self, agent_name: str, campaign_name: str, *, operation_id: Optional[str] = None, **kwargs: Any + ) -> _models.TelephonyCampaign: + """Get a telephony campaign. - Returns all transfer targets configured for the voice agent named in the path. + Gets Campaign configuration and execution state without inline recipients. Absent or deleted + Campaigns return 404. - :param agent_name: The name of the voice agent whose transfer targets are retrieved. Required. + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. :type agent_name: str - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :param campaign_name: Immutable Campaign name. Required. + :type campaign_name: str + :keyword operation_id: Original response's Operation-Id guards its instance/round and survives + same-round actions. Replacement/name reuse: 409 campaign_operation_mismatch; + missing/expired/wrong-scope operation: 404. Default value is None. + :paramtype operation_id: str + :return: TelephonyCampaign. The TelephonyCampaign is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCampaign :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -24397,10 +26876,12 @@ def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models.Teleph _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyTransferTargets] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCampaign] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_get_transfer_targets_request( + _request = build_beta_voice_agents_campaigns_get_request( agent_name=agent_name, + campaign_name=campaign_name, + operation_id=operation_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -24432,146 +26913,126 @@ def get_transfer_targets(self, agent_name: str, **kwargs: Any) -> _models.Teleph raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyTransferTargets, response.json()) + deserialized = _deserialize(_models.TelephonyCampaign, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @overload - def replace_transfer_targets( + @distributed_trace + def list( self, agent_name: str, *, - transfer_targets: List[_models.TelephonyTransferTarget], - etag: str, - match_condition: MatchConditions, - content_type: str = "application/json", + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + status: Optional[Union[str, _models.TelephonyCampaignStatus]] = None, **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + ) -> ItemPaged["_models.TelephonyCampaign"]: + """List telephony campaigns. - Replaces all transfer targets configured for the voice agent named in the path. + Lists the Agent's Campaigns without inline recipients. Filters are live views, not snapshots. - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. :type agent_name: str - :keyword transfer_targets: The complete set of destinations to which the voice agent may - transfer calls. An empty array clears all targets when replacing the configuration. Required. - :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets + :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: Opaque first_id for backward paging with unchanged scope/filters/order; + exclusive with after. Default value is None. + :paramtype before: str + :keyword status: Filter by Campaign business state. Known values are: "validating", "running", + "cancelling", "completed", "failed", "cancelled", and "deleting". Default value is None. + :paramtype status: str or ~azure.ai.projects.models.TelephonyCampaignStatus + :return: An iterator like instance of TelephonyCampaign + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyCampaign] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - def replace_transfer_targets( - self, - agent_name: str, - body: JSON, - *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + cls: ClsType[List[_models.TelephonyCampaign]] = kwargs.pop("cls", None) - Replaces all transfer targets configured for the voice agent named in the path. + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. - :type agent_name: str - :param body: Required. - :type body: JSON - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets - :raises ~azure.core.exceptions.HttpResponseError: - """ + def prepare_request(_continuation_token=None): + + _request = build_beta_voice_agents_campaigns_list_request( + agent_name=agent_name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + status=status, + 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 - @overload - def replace_transfer_targets( - self, - agent_name: str, - body: IO[bytes], - *, - etag: str, - match_condition: MatchConditions, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.TelephonyCampaign], + 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) - Replaces all transfer targets configured for the voice agent named in the path. + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - :param agent_name: The name of the voice agent whose transfer targets are replaced. Required. - :type agent_name: str - :param body: Required. - :type body: IO[bytes] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets - :raises ~azure.core.exceptions.HttpResponseError: - """ + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - @distributed_trace - def replace_transfer_targets( + 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) + + def _cancel_initial( self, agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, + campaign_name: str, *, - transfer_targets: List[_models.TelephonyTransferTarget] = _Unset, etag: str, match_condition: MatchConditions, + operation_id: Optional[str] = None, **kwargs: Any - ) -> _models.TelephonyTransferTargets: - """Replace agent telephony transfer targets. - - Replaces all transfer targets configured for the voice agent named in the path. - - :param agent_name: The name of the voice agent whose transfer targets are replaced. 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 transfer_targets: The complete set of destinations to which the voice agent may - transfer calls. An empty array clears all targets when replacing the configuration. Required. - :paramtype transfer_targets: list[~azure.ai.projects.models.TelephonyTransferTarget] - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :return: TelephonyTransferTargets. The TelephonyTransferTargets is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyTransferTargets - :raises ~azure.core.exceptions.HttpResponseError: - """ + ) -> Iterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -24586,31 +27047,18 @@ def replace_transfer_targets( error_map[412] = ResourceExistsError 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.TelephonyTransferTargets] = kwargs.pop("cls", None) - - if body is _Unset: - if transfer_targets is _Unset: - raise TypeError("missing required argument: transfer_targets") - body = {"transfer_targets": transfer_targets} - 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[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_replace_transfer_targets_request( + _request = build_beta_voice_agents_campaigns_cancel_request( agent_name=agent_name, + campaign_name=campaign_name, etag=etag, match_condition=match_condition, - content_type=content_type, + operation_id=operation_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -24620,19 +27068,18 @@ def replace_transfer_targets( _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 ) 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 [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, @@ -24641,161 +27088,147 @@ def replace_transfer_targets( raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + 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.TelephonyTransferTargets, response.json()) + 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_call_job( - self, - agent_name: str, - body: _models.CreateTelephonyCallJobRequest, - *, - idempotency_key: str, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. - - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. - - :param agent_name: The name of the voice agent that executes the call. Required. - :type agent_name: str - :param body: The direct outbound call to create. Required. - :type body: ~azure.ai.projects.models.CreateTelephonyCallJobRequest - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_call_job( + @distributed_trace + def begin_cancel( self, agent_name: str, - body: JSON, + campaign_name: str, *, - idempotency_key: str, - content_type: str = "application/json", + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. + ) -> LROPoller[_models.TelephonyCampaign]: + """Cancel a telephony campaign. - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + Cancels a validating or running Campaign using If-Match. Stops new calls and retries; connected + calls finish naturally. Returns 202 with an operation monitor to track completion. - :param agent_name: The name of the voice agent that executes the call. Required. + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. :type agent_name: str - :param body: The direct outbound call to create. Required. - :type body: JSON - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :param campaign_name: Campaign name. Required. + :type campaign_name: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key, generated if omitted. Original If-Match/key replays + 202 even after deletion/name reuse, never touching a replacement; conflicts return 409. Failed + cancellation needs a fresh key/current token. Default value is None. + :paramtype operation_id: str + :return: An instance of LROPoller that returns TelephonyCampaign. The TelephonyCampaign is + compatible with MutableMapping + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - def create_call_job( - self, - agent_name: str, - body: IO[bytes], - *, - idempotency_key: str, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. - - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + cls: ClsType[_models.TelephonyCampaign] = 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._cancel_initial( + agent_name=agent_name, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + cls=lambda x, y, z: x, + headers=_headers, + params=_params, + **kwargs + ) + raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) - :param agent_name: The name of the voice agent that executes the call. Required. - :type agent_name: str - :param body: The direct outbound call to create. Required. - :type body: IO[bytes] - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_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: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + def get_long_running_output(pipeline_response): + response_headers = {} + response = pipeline_response.http_response + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) - @distributed_trace - def create_call_job( - self, - agent_name: str, - body: Union[_models.CreateTelephonyCallJobRequest, JSON, IO[bytes]], - *, - idempotency_key: str, - **kwargs: Any - ) -> _models.TelephonyCallJob: - """Create an outbound telephony call job. + deserialized = _deserialize(_models.TelephonyCampaign, response.json()) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized - Creates one durable direct outbound call job. The latest agent definition is resolved when each - attempt executes. + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } - :param agent_name: The name of the voice agent that executes the call. Required. - :type agent_name: str - :param body: The direct outbound call to create. Is one of the following types: - CreateTelephonyCallJobRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.CreateTelephonyCallJobRequest or JSON or IO[bytes] - :keyword idempotency_key: A customer-generated idempotency key. Reusing it with an equivalent - request returns the same call job. Required. - :paramtype idempotency_key: str - :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + 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.TelephonyCampaign].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return LROPoller[_models.TelephonyCampaign]( + self._client, raw_result, get_long_running_output, polling_method # type: ignore + ) + + def _delete_initial( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> Iterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, 304: ResourceNotModifiedError, } + if match_condition == MatchConditions.IfNotModified: + error_map[412] = ResourceModifiedError + elif match_condition == MatchConditions.IfPresent: + error_map[412] = ResourceNotFoundError + elif match_condition == MatchConditions.IfMissing: + error_map[412] = ResourceExistsError 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.TelephonyCallJob] = 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[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_create_call_job_request( + _request = build_beta_voice_agents_campaigns_delete_request( agent_name=agent_name, - idempotency_key=idempotency_key, - content_type=content_type, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -24805,19 +27238,18 @@ def create_call_job( _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 ) response = pipeline_response.http_response - 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 + if response.status_code not in [202, 204]: + 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, @@ -24826,14 +27258,15 @@ def create_call_job( raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - response_headers["Retry-After"] = self._deserialize("duration-seconds-int", response.headers.get("Retry-After")) + if response.status_code == 202: + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + response_headers["Operation-Id"] = self._deserialize("str", response.headers.get("Operation-Id")) + 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.TelephonyCallJob, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -24841,19 +27274,127 @@ def create_call_job( return deserialized # type: ignore @distributed_trace - def get_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) -> _models.TelephonyCallJob: - """Get an outbound telephony call job. + def begin_delete( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> LROPoller[None]: + """Delete a telephony campaign. - Retrieves a durable direct or campaign-created outbound call job. + Deletes a terminal Campaign and its recipient/task data asynchronously. Returns bodyless 202 + with a monitor, not a tombstone; completion makes GET return 404 and lists omit it. Dataset, + connections, Agent, independent jobs and call history are preserved. - :param agent_name: Required. + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. :type agent_name: str - :param call_job_id: Required. - :type call_job_id: str - :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :param campaign_name: Immutable Campaign name. Required. + :type campaign_name: str + :keyword etag: check if resource is changed. Set None to skip checking etag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use upon the etag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key. Original If-Match/key replays 202 even after + deletion/name reuse, never touching a new instance; conflicts return 409. Failed cleanup needs + a fresh key/current token. Default value is None. + :paramtype operation_id: str + :return: An instance of LROPoller that returns None + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = 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._delete_initial( + agent_name=agent_name, + campaign_name=campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + 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): # pylint: disable=inconsistent-return-statements + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + + 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[None].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return LROPoller[None](self._client, raw_result, get_long_running_output, polling_method) # type: ignore + + @distributed_trace + def list_validation_errors( + self, + agent_name: str, + campaign_name: str, + *, + limit: Optional[int] = None, + before: Optional[str] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + **kwargs: Any + ) -> ItemPaged["_models.TelephonyCampaignValidationError"]: + """List campaign validation errors. + + Lists current-round row validation errors. Results may be partial during preparation; an empty + page does not establish success. Execution errors are in CallJobs; non-row failures are in + Campaign.error. + + :param agent_name: Owning Agent; never overridden in recipient inputs. Required. + :type agent_name: str + :param campaign_name: Campaign name. Deleting returns 409 campaign_deleting; absent/deleted + returns 404. Required. + :type campaign_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 before: Opaque first_id for backward paging with unchanged scope/filters/order; + exclusive with after. Default value is None. + :paramtype before: str + :keyword order: Sort invalid rows by their original row_number. Known values are: "asc" and + "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :return: An iterator like instance of TelephonyCampaignValidationError + :rtype: + ~azure.core.paging.ItemPaged[~azure.ai.projects.models.TelephonyCampaignValidationError] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.TelephonyCampaignValidationError]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -24862,75 +27403,75 @@ def get_call_job(self, agent_name: str, call_job_id: str, **kwargs: Any) -> _mod } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) + def prepare_request(_continuation_token=None): - _request = build_beta_voice_agents_telephony_get_call_job_request( - agent_name=agent_name, - call_job_id=call_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) + _request = build_beta_voice_agents_campaigns_list_validation_errors_request( + agent_name=agent_name, + campaign_name=campaign_name, + limit=limit, + after=_continuation_token, + before=before, + order=order, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.TelephonyCampaignValidationError], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) - response = pipeline_response.http_response + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return pipeline_response - return deserialized # type: ignore + return ItemPaged(get_next, extract_data) @distributed_trace - def cancel_call_job( - self, agent_name: str, call_job_id: str, *, etag: str, match_condition: MatchConditions, **kwargs: Any - ) -> _models.TelephonyCallJob: - """Cancel an outbound telephony call job. + def get_operation( + self, agent_name: str, campaign_name: str, operation_id: str, **kwargs: Any + ) -> _models.TelephonyCampaignOperation: + """Get a campaign operation. - Requests cancellation of a durable outbound call job. A connected call is allowed to finish. + Gets the initiating operation's status. PUT/cancel pollers finish with a guarded Campaign GET; + deletion completes without a resource result. - :param agent_name: Required. + :param agent_name: Owning Agent. Required. :type agent_name: str - :param call_job_id: Required. - :type call_job_id: str - :keyword etag: check if resource is changed. Set None to skip checking etag. Required. - :paramtype etag: str - :keyword match_condition: The match condition to use upon the etag. Required. - :paramtype match_condition: ~azure.core.MatchConditions - :return: TelephonyCallJob. The TelephonyCallJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.TelephonyCallJob + :param campaign_name: Immutable Campaign name. Required. + :type campaign_name: str + :param operation_id: Operation-Id from the initiating response. Saved project/Agent + authorization still applies after resource deletion. Required. + :type operation_id: str + :return: TelephonyCampaignOperation. The TelephonyCampaignOperation is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.TelephonyCampaignOperation :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -24939,24 +27480,17 @@ def cancel_call_job( 409: ResourceExistsError, 304: ResourceNotModifiedError, } - if match_condition == MatchConditions.IfNotModified: - error_map[412] = ResourceModifiedError - elif match_condition == MatchConditions.IfPresent: - error_map[412] = ResourceNotFoundError - elif match_condition == MatchConditions.IfMissing: - error_map[412] = ResourceExistsError error_map.update(kwargs.pop("error_map", {}) or {}) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.TelephonyCallJob] = kwargs.pop("cls", None) + cls: ClsType[_models.TelephonyCampaignOperation] = kwargs.pop("cls", None) - _request = build_beta_voice_agents_telephony_cancel_call_job_request( + _request = build_beta_voice_agents_campaigns_get_operation_request( agent_name=agent_name, - call_job_id=call_job_id, - etag=etag, - match_condition=match_condition, + campaign_name=campaign_name, + operation_id=operation_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -24974,7 +27508,7 @@ def cancel_call_job( response = pipeline_response.http_response - if response.status_code not in [200, 202]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -24988,20 +27522,13 @@ def cancel_call_job( raise HttpResponseError(response=response, model=error) response_headers = {} - if response.status_code == 200: - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - - if response.status_code == 202: - response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - response_headers["Retry-After"] = self._deserialize( - "duration-seconds-int", response.headers.get("Retry-After") - ) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.TelephonyCallJob, response.json()) + deserialized = _deserialize(_models.TelephonyCampaignOperation, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # 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 a29e31ebd39b..535c7257d534 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 @@ -20,6 +20,7 @@ ConversationItem, ServerEvent, ) +from .._live import BetaLive, BetaLiveConnection, BetaLiveConnectionManager, LiveClientEvent, LiveServerEvent from ._patch_agents import AgentsOperations, BetaAgentsOperations from ._patch_agent_insights import BetaAgentInsightMonitorsOperations from ._patch_datasets import DatasetsOperations @@ -29,6 +30,9 @@ from ._patch_connections import ConnectionsOperations from ._patch_memories import BetaMemoryStoresOperations from ._patch_models import BetaModelsOperations +from ._patch_campaigns import BetaVoiceAgentsCampaignsOperations + +# Nested operation groups are re-exported here rather than in the generated package exports. from ._operations import ( BetaEvaluationTaxonomiesOperations, BetaInsightsOperations, @@ -38,6 +42,7 @@ BetaSchedulesOperations, BetaSkillsOperations, BetaVoiceAgentsConversationsOperations, + BetaVoiceAgentsLiveConversationsOperations, BetaVoiceAgentsOperations as GeneratedBetaVoiceAgentsOperations, BetaVoiceAgentsTelephonyOperations, ) @@ -131,19 +136,29 @@ class BetaVoiceAgentsOperations(GeneratedBetaVoiceAgentsOperations): :attr:`~azure.ai.projects.operations.BetaOperations.voice_agents` attribute. """ + campaigns: BetaVoiceAgentsCampaignsOperations + """:class:`~azure.ai.projects.operations.BetaVoiceAgentsCampaignsOperations` operations""" conversations: BetaVoiceAgentsConversationsOperations """:class:`~azure.ai.projects.operations.BetaVoiceAgentsConversationsOperations` operations""" + live_conversations: BetaVoiceAgentsLiveConversationsOperations + """:class:`~azure.ai.projects.operations.BetaVoiceAgentsLiveConversationsOperations` operations""" telephony: BetaVoiceAgentsTelephonyOperations """:class:`~azure.ai.projects.operations.BetaVoiceAgentsTelephonyOperations` operations""" realtime: BetaRealtime """:class:`~azure.ai.projects.operations.BetaRealtime` operations""" + live: BetaLive + """:class:`~azure.ai.projects.operations.BetaLive` operations""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.campaigns = BetaVoiceAgentsCampaignsOperations( + self._client, self._config, self._serialize, self._deserialize + ) # The generator does not emit realtime operations at all, since azure-core's HTTP # pipeline has no way to keep a WebSocket upgrade's resulting socket alive. Add our # hand-written client, which manages a real, long-lived connection, in its place. self.realtime = BetaRealtime(self) + self.live = BetaLive(self) class BetaOperations(GeneratedBetaOperations): @@ -215,7 +230,9 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "BetaRoutinesOperations", "BetaSchedulesOperations", "BetaSkillsOperations", + "BetaVoiceAgentsCampaignsOperations", "BetaVoiceAgentsConversationsOperations", + "BetaVoiceAgentsLiveConversationsOperations", "BetaVoiceAgentsOperations", "BetaVoiceAgentsTelephonyOperations", "ClientEvent", @@ -227,6 +244,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "BetaRealtime", "BetaRealtimeConnection", "BetaRealtimeConnectionManager", + "BetaLive", + "BetaLiveConnection", + "BetaLiveConnectionManager", + "LiveClientEvent", + "LiveServerEvent", "ServerEvent", "TelemetryOperations", ] # Add all objects you want publicly available to users at this package level diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_campaigns.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_campaigns.py new file mode 100644 index 000000000000..af7434e26d51 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_campaigns.py @@ -0,0 +1,198 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Custom Voice Agent campaign operations.""" + +from collections.abc import MutableMapping +from typing import Any, IO, Optional, Union, overload + +from azure.core import MatchConditions +from azure.core.polling import LROPoller + +from ._operations import BetaVoiceAgentsCampaignsOperations as GeneratedBetaVoiceAgentsCampaignsOperations +from .. import models as _models +from .._utils.campaign_polling import _configure_campaign_polling + +JSON = MutableMapping[str, Any] + + +class BetaVoiceAgentsCampaignsOperations(GeneratedBetaVoiceAgentsCampaignsOperations): + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, access these operations through + :class:`~azure.ai.projects.AIProjectClient`'s ``beta.voice_agents.campaigns`` attribute. + """ + + def _configure_polling(self, kwargs: dict[str, Any]) -> None: + _configure_campaign_polling( + kwargs, + self._config.polling_interval, + {"endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True)}, + ) + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: _models.TelephonyCampaign, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> LROPoller[_models.TelephonyCampaign]: ... + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: JSON, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> LROPoller[_models.TelephonyCampaign]: ... + + @overload + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> LROPoller[_models.TelephonyCampaign]: ... + + def begin_create( + self, + agent_name: str, + campaign_name: str, + campaign: Union[_models.TelephonyCampaign, JSON, IO[bytes]], + *, + operation_id: Optional[str] = None, + etag: Optional[str] = None, + match_condition: Optional[MatchConditions] = None, + **kwargs: Any, + ) -> LROPoller[_models.TelephonyCampaign]: + """Create or replace a failed telephony campaign. + + All recipients must validate and have CallJobs before dialing. Immediate calls may + begin before preparation finishes. The final Campaign GET is guarded by the initiating + operation ID. + + :param agent_name: Owning Agent. Required. + :type agent_name: str + :param campaign_name: Campaign name. Only failed preparation permits replacement. Required. + :type campaign_name: str + :param campaign: Complete campaign configuration. Required. + :type campaign: ~azure.ai.projects.models.TelephonyCampaign or MutableMapping[str, Any] or IO[bytes] + :keyword operation_id: Optional retry key. Conflicting reuse returns an error. + :paramtype operation_id: str + :keyword etag: Resource ETag used with ``match_condition``. + :paramtype etag: str + :keyword match_condition: The match condition to use with the ETag. + :paramtype match_condition: ~azure.core.MatchConditions + :return: A poller returning the Campaign after preparation. + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._configure_polling(kwargs) + return super().begin_create( + agent_name, + campaign_name, + campaign, + operation_id=operation_id, + etag=etag, + match_condition=match_condition, + **kwargs, + ) + + def begin_cancel( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any, + ) -> LROPoller[_models.TelephonyCampaign]: + """Cancel a validating or running telephony campaign. + + Stops new calls and retries; connected calls finish naturally. The final Campaign GET + is guarded by the initiating operation ID. + + :param agent_name: Owning Agent. Required. + :type agent_name: str + :param campaign_name: Campaign name. Required. + :type campaign_name: str + :keyword etag: Exact current Campaign ETag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use with the ETag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key. + :paramtype operation_id: str + :return: A poller returning the Campaign after cancellation. + :rtype: ~azure.core.polling.LROPoller[~azure.ai.projects.models.TelephonyCampaign] + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._configure_polling(kwargs) + return super().begin_cancel( + agent_name, + campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + **kwargs, + ) + + def begin_delete( + self, + agent_name: str, + campaign_name: str, + *, + etag: str, + match_condition: MatchConditions, + operation_id: Optional[str] = None, + **kwargs: Any, + ) -> LROPoller[None]: + """Delete a terminal telephony campaign and its recipient/task data. + + Completion does not fetch the deleted Campaign. Dataset, connections, Agent, + independent jobs, and call history are preserved. + + :param agent_name: Owning Agent. Required. + :type agent_name: str + :param campaign_name: Campaign name. Required. + :type campaign_name: str + :keyword etag: Exact current Campaign ETag. Required. + :paramtype etag: str + :keyword match_condition: The match condition to use with the ETag. Required. + :paramtype match_condition: ~azure.core.MatchConditions + :keyword operation_id: Optional retry key. + :paramtype operation_id: str + :return: A poller returning None after deletion. + :rtype: ~azure.core.polling.LROPoller[None] + :raises ~azure.core.exceptions.HttpResponseError: + """ + self._configure_polling(kwargs) + return super().begin_delete( + agent_name, + campaign_name, + etag=etag, + match_condition=match_condition, + operation_id=operation_id, + **kwargs, + ) diff --git a/sdk/ai/azure-ai-projects/docs/GeneratePublicMethodsDoc.ps1 b/sdk/ai/azure-ai-projects/docs/GeneratePublicMethodsDoc.ps1 index b1d3017632f5..1e5f70540895 100644 --- a/sdk/ai/azure-ai-projects/docs/GeneratePublicMethodsDoc.ps1 +++ b/sdk/ai/azure-ai-projects/docs/GeneratePublicMethodsDoc.ps1 @@ -57,7 +57,7 @@ def unwrap_operation(value: Any) -> Any: # Hand-written sub-client classes that don't follow the generated *Operations naming # convention but are still part of the public surface and should be discovered/counted the # same way, e.g. `beta.voice_agents.realtime` (`BetaRealtime`/`AsyncBetaRealtime`). -_HANDWRITTEN_SUBCLIENT_CLASS_NAMES = {"BetaRealtime", "AsyncBetaRealtime"} +_HANDWRITTEN_SUBCLIENT_CLASS_NAMES = {"BetaRealtime", "AsyncBetaRealtime", "BetaLive", "AsyncBetaLive"} def _is_operation_group(value: Any) -> bool: diff --git a/sdk/ai/azure-ai-projects/docs/public-methods.md b/sdk/ai/azure-ai-projects/docs/public-methods.md index 1af36d277b6f..7b17fb38ea82 100644 --- a/sdk/ai/azure-ai-projects/docs/public-methods.md +++ b/sdk/ai/azure-ai-projects/docs/public-methods.md @@ -6,11 +6,11 @@ This document lists all public methods available on `AIProjectClient` and its su ## Summary -There are a total of 192 unique public methods: +There are a total of 211 unique public methods: - 5 stable methods on the client - 84 stable methods on top-level sub-clients -- 103 beta methods on nested beta sub-clients +- 122 beta methods on nested beta sub-clients ### Top-level sub-clients (stable operations) @@ -41,9 +41,12 @@ There are a total of 192 unique public methods: | `beta.routines` | BetaRoutinesOperations | 8 | | `beta.schedules` | BetaSchedulesOperations | 6 | | `beta.skills` | BetaSkillsOperations | 11 | +| `beta.voice_agents.campaigns` | BetaVoiceAgentsCampaignsOperations | 7 | | `beta.voice_agents.conversations` | BetaVoiceAgentsConversationsOperations | 14 | +| `beta.voice_agents.live` | BetaLive | 1 | +| `beta.voice_agents.live_conversations` | BetaVoiceAgentsLiveConversationsOperations | 9 | | `beta.voice_agents.realtime` | BetaRealtime | 1 | -| `beta.voice_agents.telephony` | BetaVoiceAgentsTelephonyOperations | 14 | +| `beta.voice_agents.telephony` | BetaVoiceAgentsTelephonyOperations | 16 | ## Stable methods on the client @@ -246,6 +249,14 @@ Alphabetically sorted. An asterisk at the end of the method name means it is a h .beta.skills.list_versions .beta.skills.update +.beta.voice_agents.campaigns.begin_cancel* +.beta.voice_agents.campaigns.begin_create* +.beta.voice_agents.campaigns.begin_delete* +.beta.voice_agents.campaigns.get +.beta.voice_agents.campaigns.get_operation +.beta.voice_agents.campaigns.list +.beta.voice_agents.campaigns.list_validation_errors + .beta.voice_agents.conversations.delete .beta.voice_agents.conversations.download_audio .beta.voice_agents.conversations.download_audio_item @@ -261,18 +272,32 @@ Alphabetically sorted. An asterisk at the end of the method name means it is a h .beta.voice_agents.conversations.list_response_items .beta.voice_agents.conversations.list_responses +.beta.voice_agents.live.connect* + +.beta.voice_agents.live_conversations.delete +.beta.voice_agents.live_conversations.download_audio +.beta.voice_agents.live_conversations.download_audio_item +.beta.voice_agents.live_conversations.get +.beta.voice_agents.live_conversations.get_audio +.beta.voice_agents.live_conversations.get_audio_item +.beta.voice_agents.live_conversations.get_item +.beta.voice_agents.live_conversations.list +.beta.voice_agents.live_conversations.list_items + .beta.voice_agents.realtime.connect* .beta.voice_agents.telephony.cancel_call_job .beta.voice_agents.telephony.create_binding .beta.voice_agents.telephony.create_call_job .beta.voice_agents.telephony.delete_binding +.beta.voice_agents.telephony.delete_call_job .beta.voice_agents.telephony.end_call .beta.voice_agents.telephony.get_binding .beta.voice_agents.telephony.get_call .beta.voice_agents.telephony.get_call_job .beta.voice_agents.telephony.get_transfer_targets .beta.voice_agents.telephony.list_bindings +.beta.voice_agents.telephony.list_call_jobs .beta.voice_agents.telephony.list_calls .beta.voice_agents.telephony.replace_transfer_targets .beta.voice_agents.telephony.transfer_call diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/audio/question.wav b/sdk/ai/azure-ai-projects/samples/agents/voice/audio/question.wav new file mode 100644 index 000000000000..90f7c3d94030 Binary files /dev/null and b/sdk/ai/azure-ai-projects/samples/agents/voice/audio/question.wav differ diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/live_sample_utils.py b/sdk/ai/azure-ai-projects/samples/agents/voice/live_sample_utils.py new file mode 100644 index 000000000000..144521006ddd --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/live_sample_utils.py @@ -0,0 +1,276 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Shared lifecycle and event helpers for the GPT Live samples in this folder.""" + +from __future__ import annotations + +import asyncio +from contextlib import contextmanager, suppress +import os +from pathlib import Path +import sys +import time +from typing import Any, BinaryIO, Iterator, Mapping, Optional, Sequence, TYPE_CHECKING +from uuid import uuid4 + +from azure.ai.projects import models + +if TYPE_CHECKING: + from azure.ai.projects.operations import BetaLiveConnection, LiveServerEvent + from azure.ai.projects.aio.operations import AsyncBetaLiveConnection + + +RESPONSE_TIMEOUT = 60.0 +CLOSE_TIMEOUT = 10.0 + + +def input_audio_path() -> Path: + """Use the bundled spoken question unless a different WAV is supplied.""" + default = Path(__file__).parent / "audio" / "question.wav" + return Path(os.environ.get("FOUNDRY_VOICE_AUDIO_INPUT_PATH") or default) + + +def sample_agent_name(scenario: str) -> str: + """Choose a unique agent name so cleanup affects only this run.""" + prefix = os.environ.get("FOUNDRY_VOICE_AGENT_NAME") or f"sample-live-{scenario}" + return f"{prefix}-{uuid4().hex[:8]}" + + +def text_conversation_prompts(prompts: Optional[Sequence[str]]) -> list[str]: + """Use one default message, or validate the supplied list of messages.""" + if prompts is None: + return ["Why is Seattle known for rain? Answer in one short sentence."] + if isinstance(prompts, str): + raise ValueError("Pass prompts as a sequence of strings, not one string.") + result = list(prompts) + if not result or any(not isinstance(prompt, str) or not prompt.strip() for prompt in result): + raise ValueError("Provide at least one nonblank text prompt.") + return result + + +def audio_settings() -> models.LiveInitialSessionAudioParam: + """Use the same PCM16, mono, 24 kHz format in both directions.""" + return models.LiveInitialSessionAudioParam( + format=models.LiveSessionAudioFormatPCMParam(rate=24000), + output=models.LiveInitialSessionAudioOutputParam(voice="marin"), + ) + + +def safe_print(text: str, *, end: str = "\n") -> None: + """Display model text even on a console with a legacy encoding.""" + encoding = sys.stdout.encoding or "utf-8" + print(text.encode(encoding, errors="replace").decode(encoding), end=end, flush=True) + + +@contextmanager +def recording_output(path: Path) -> Iterator[BinaryIO]: + """Save a recording without overwriting a file; remove failed or empty downloads. + + :param path: Explicit destination that must not already exist. + :type path: pathlib.Path + :return: A writable binary stream for the downloaded audio. + :rtype: ~typing.Iterator[~typing.BinaryIO] + """ + output = path.open("xb") + completed = False + try: + with output: + yield output + if output.tell() == 0: + raise RuntimeError("The audio download returned no bytes.") + completed = True + finally: + if not completed: + path.unlink() + print(f"Saved recording: {path}") + + +def remaining_time(deadline: float, operation: str) -> float: + """Return the time left, or raise when the deadline expires.""" + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError(f"Timed out waiting for {operation}.") + return remaining + + +def check_event(event: LiveServerEvent) -> Mapping[str, Any]: + """Raise service errors and read events from the Responses backend.""" + if event.get("type") == "error": + error = event.get("error") or {} + raise RuntimeError(f"Live session error: {error.get('code')}: {error.get('message')}") + + if isinstance(event, models.LiveServerEventLiveResponseEvent): + nested: Mapping[str, Any] = event.event + elif event.get("type") == "response.event": + nested = event["event"] + else: + return {} + + response = nested.get("response") or {} + status = response.get("status") + if nested.get("type") in ("error", "response.failed", "response.incomplete", "response.cancelled") or status in ( + "failed", + "incomplete", + "cancelled", + ): + detail = nested.get("error") or response.get("error") or response.get("incomplete_details") + raise RuntimeError(f"Responses backend {nested.get('type')}: {detail or status or 'unknown error'}") + return nested + + +def check_session_open(event: LiveServerEvent) -> None: + """Raise if the session closes before the requested work finishes.""" + if event.get("type") == "session.closed": + raise RuntimeError(f"Live session closed before the workflow completed: {event.get('reason')}") + + +def wait_for_event( + connection: BetaLiveConnection, event_type: str, timeout: float = RESPONSE_TIMEOUT +) -> LiveServerEvent: + """Wait for a specific event, with a timeout.""" + deadline = time.monotonic() + timeout + while True: + try: + event = connection.recv(timeout=remaining_time(deadline, event_type)) + except TimeoutError as exc: + raise TimeoutError(f"Timed out waiting for {event_type}.") from exc + check_event(event) + if event.get("type") == event_type: + return event + check_session_open(event) + + +async def wait_for_event_with_audio_clock_async( + connection: AsyncBetaLiveConnection, event_type: str, timeout: float = RESPONSE_TIMEOUT +) -> LiveServerEvent: + """Keep the Live timeline advancing while waiting for a context acknowledgement.""" + deadline = time.monotonic() + timeout + next_frame = time.monotonic() + silence = bytes(2400) # 50 ms of PCM16, mono, 24 kHz audio. + while True: + remaining_time(deadline, event_type) + if time.monotonic() >= next_frame: + await connection.session.input_audio.append(audio=silence) + next_frame = time.monotonic() + 0.05 + receive_timeout = min(remaining_time(deadline, event_type), next_frame - time.monotonic()) + if receive_timeout <= 0: + continue + try: + event = await asyncio.wait_for(connection.recv(), timeout=receive_timeout) + except (asyncio.TimeoutError, TimeoutError): + continue + check_event(event) + if event.get("type") == event_type: + return event + check_session_open(event) + + +async def wait_for_event_async( + connection: AsyncBetaLiveConnection, event_type: str, timeout: float = RESPONSE_TIMEOUT +) -> LiveServerEvent: + """Wait asynchronously for a specific event, with a timeout.""" + deadline = time.monotonic() + timeout + while True: + try: + remaining = remaining_time(deadline, event_type) + event = await asyncio.wait_for(connection.recv(), timeout=remaining) + except (asyncio.TimeoutError, TimeoutError) as exc: + raise TimeoutError(f"Timed out waiting for {event_type}.") from exc + check_event(event) + if event.get("type") == event_type: + return event + check_session_open(event) + + +def close_session(connection: BetaLiveConnection) -> None: + """Close the session without hiding an error already being handled.""" + if sys.exc_info()[0] is not None: + with suppress(Exception): + connection.session.close() + return + connection.session.close() + event = wait_for_event(connection, "session.closed", timeout=CLOSE_TIMEOUT) + if event.get("reason") != "close_requested": + raise RuntimeError(f"Live session did not close normally: {event.get('reason')}") + print("Session closed: close_requested") + + +async def close_session_async(connection: AsyncBetaLiveConnection) -> None: + """End the session before closing its WebSocket.""" + if sys.exc_info()[0] is not None: + with suppress(Exception): + await asyncio.wait_for(connection.session.close(), timeout=CLOSE_TIMEOUT) + return + deadline = time.monotonic() + CLOSE_TIMEOUT + try: + remaining = remaining_time(deadline, "session.close") + await asyncio.wait_for(connection.session.close(), timeout=remaining) + event = await wait_for_event_async( + connection, "session.closed", timeout=remaining_time(deadline, "session.closed") + ) + except (asyncio.TimeoutError, TimeoutError) as exc: + raise TimeoutError("Timed out closing the GPT Live session.") from exc + if event.get("reason") != "close_requested": + raise RuntimeError(f"Live session did not close normally: {event.get('reason')}") + print("Session closed: close_requested") + + +def _collect_response_event( + event: LiveServerEvent, + text_parts: dict[tuple[str, int], str], + calls: dict[str, Mapping[str, Any]], +) -> bool: + nested = check_event(event) + check_session_open(event) + event_type = nested.get("type") + if event_type in ("response.output_text.delta", "response.output_text.done"): + key = (nested["item_id"], nested["content_index"]) + if event_type == "response.output_text.delta": + text_parts[key] = text_parts.get(key, "") + nested["delta"] + else: + text_parts[key] = nested["text"] + elif event_type == "response.output_item.done": + item = nested["item"] + if item.get("type") == "function_call": + # Argument events identify item_id; the complete item supplies the tool-result call_id. + call_id = item.get("call_id") + if not isinstance(call_id, str) or not call_id: + raise RuntimeError("The completed Responses function_call item omitted a usable call_id.") + calls[call_id] = item + return event_type == "response.completed" + + +def receive_response( + connection: BetaLiveConnection, timeout: float = RESPONSE_TIMEOUT +) -> tuple[str, list[Mapping[str, Any]]]: + """Wait for a backend reply and return its text and completed tool calls.""" + deadline = time.monotonic() + timeout + text_parts: dict[tuple[str, int], str] = {} + calls: dict[str, Mapping[str, Any]] = {} + while True: + try: + event = connection.recv(timeout=remaining_time(deadline, "the Responses backend")) + except TimeoutError as exc: + raise TimeoutError("Timed out waiting for the Responses backend to complete.") from exc + if _collect_response_event(event, text_parts, calls): + # Text and tool results arrive before response.completed. + return "".join(text_parts.values()).strip(), list(calls.values()) + + +async def receive_response_async( + connection: AsyncBetaLiveConnection, timeout: float = RESPONSE_TIMEOUT +) -> tuple[str, list[Mapping[str, Any]]]: + """Wait asynchronously for a backend reply and its completed tool calls.""" + deadline = time.monotonic() + timeout + text_parts: dict[tuple[str, int], str] = {} + calls: dict[str, Mapping[str, Any]] = {} + while True: + try: + remaining = remaining_time(deadline, "the Responses backend") + event = await asyncio.wait_for(connection.recv(), timeout=remaining) + except (asyncio.TimeoutError, TimeoutError) as exc: + raise TimeoutError("Timed out waiting for the Responses backend to complete.") from exc + if _collect_response_event(event, text_parts, calls): + return "".join(text_parts.values()).strip(), list(calls.values()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/managed_agent_sample_utils.py b/sdk/ai/azure-ai-projects/samples/agents/voice/managed_agent_sample_utils.py new file mode 100644 index 000000000000..e2bd6f8e2948 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/managed_agent_sample_utils.py @@ -0,0 +1,260 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Audio and event handling shared only by the managed prompt-agent Live samples.""" + +from __future__ import annotations + +import asyncio +import base64 +from collections.abc import Mapping +from dataclasses import dataclass, field +from pathlib import Path +import time +from typing import Any, TYPE_CHECKING +import wave + +from azure.ai.projects import models + +from live_sample_utils import ( + RESPONSE_TIMEOUT, + audio_settings, + check_event, + check_session_open, + remaining_time, + safe_print, +) + +if TYPE_CHECKING: + from azure.ai.projects.operations import BetaLiveConnection, LiveServerEvent + from azure.ai.projects.aio.operations import AsyncBetaLiveConnection + + +SAMPLE_RATE = 24000 +CHUNK_BYTES = 2400 # 50 ms of mono PCM16. +MAX_INPUT_SECONDS = 30 +OUTPUT_IDLE_SECONDS = 3.0 +_SILENCE = bytes(CHUNK_BYTES) + +PROMPT_INSTRUCTIONS = ( + "You answer spoken questions delegated by a voice assistant. Return exactly two text sections: " + "start with the literal marker [thinking] and a brief task status, not private reasoning; " + "then the literal marker [commentary] and the actual answer in one short, speakable sentence. " + "Do not use Markdown fences. Do not claim to have used tools or external sources." +) + + +def read_input_audio(path: Path) -> bytes: + """Validate the entire short WAV before creating either service resource.""" + try: + with wave.open(str(path), "rb") as recording: + if ( + recording.getnchannels() != 1 + or recording.getsampwidth() != 2 + or recording.getframerate() != SAMPLE_RATE + or recording.getcomptype() != "NONE" + ): + raise ValueError("FOUNDRY_VOICE_AUDIO_INPUT_PATH must be an uncompressed PCM16, mono, 24000 Hz WAV.") + frames = recording.getnframes() + if not 0 < frames <= SAMPLE_RATE * MAX_INPUT_SECONDS: + raise ValueError(f"The input WAV must contain between one frame and {MAX_INPUT_SECONDS} seconds.") + pcm = recording.readframes(frames + 1) + if len(pcm) != frames * 2: + raise ValueError("The input WAV has truncated or incomplete PCM16 frames.") + except (wave.Error, EOFError) as exc: + raise ValueError("FOUNDRY_VOICE_AUDIO_INPUT_PATH must be a readable PCM16 WAV file.") from exc + if not _has_audio_activity(pcm): + raise ValueError("The input WAV must contain audible spoken audio, not only silence.") + return pcm + + +def live_definition(model: str, backend_name: str, backend_version: str) -> models.VoiceAgentLiveDefinition: + """Pin delegation to the exact prompt-agent version created in this project.""" + return models.VoiceAgentLiveDefinition( + model_type=models.VoiceModelType.SELF_DEPLOYED, + model=model, + instructions=( + "You are a friendly voice assistant. Delegate every substantive spoken question to your backend. " + "Do not answer from your own knowledge or give a spoken acknowledgement. " + "Wait for backend guidance, then speak its answer in one short sentence." + ), + audio=audio_settings(), + delegation=models.VoiceAgentLiveManagedAgentDelegation(agent_name=backend_name, agent_version=backend_version), + store=False, + ) + + +def check_managed_session(session: models.VoiceAgentLiveSessionResource, name: str, version: str) -> None: + """Inspect opaque session ownership metadata, not a persisted-definition DTO.""" + if not isinstance(session, models.VoiceAgentLiveSessionResource): + raise RuntimeError("The Live session did not contain a typed session snapshot.") + owner = session.delegation + if ( + not isinstance(owner, Mapping) + or owner.get("type") != "foundry_managed_agent" + or owner.get("agent_name") != name + or owner.get("agent_version") != version + ): + raise RuntimeError("The Live session did not pin the expected same-project prompt-agent version.") + print(f"Foundry owns delegation to prompt agent {owner['agent_name']}, version {owner['agent_version']}.") + + +def _has_audio_activity(pcm: bytes) -> bool: + return any( + abs(int.from_bytes(pcm[index : index + 2], "little", signed=True)) > 256 for index in range(0, len(pcm), 2) + ) + + +def _checked_event(event: LiveServerEvent) -> Mapping[str, Any]: + if event.get("type") == "error" and not isinstance(event.get("error"), Mapping): + raise RuntimeError("Malformed Live session error event.") + if event.get("type") == "response.event": + nested = event.get("event") + if not isinstance(nested, Mapping) or not isinstance(nested.get("type"), str) or not nested["type"]: + raise RuntimeError("Malformed managed backend response.event.") + if "response" in nested and not isinstance(nested["response"], Mapping): + raise RuntimeError("Malformed managed backend response snapshot.") + nested = check_event(event) + check_session_open(event) + return nested + + +@dataclass +class ManagedReply: + """Observed backend completion and actual frontend audio are separate conditions.""" + + last_activity: float + delegations: dict[str, bool] = field(default_factory=dict) + audio_bytes: int = 0 + audio_chunks: int = 0 + input_transcript: str = "" + output_transcript: str = "" + _audio_after_delegation: bool = False + _transcript_after_delegation: bool = False + + def observe(self, event: LiveServerEvent, now: float) -> None: + nested = _checked_event(event) + if isinstance(event, models.LiveServerEventLiveDelegationCreated): + delegation = event.delegation + if ( + not isinstance(delegation, models.VoiceAgentLiveDelegationItem) + or delegation.target != "foundry_managed_agent" + or not delegation.id + ): + raise RuntimeError("Expected a Foundry-owned managed-agent delegation, not client-owned work.") + if delegation.id not in self.delegations: + self.delegations[delegation.id] = False + self._audio_after_delegation = False + self._transcript_after_delegation = False + self.last_activity = now + target = getattr(delegation.target, "value", delegation.target) + print(f"Delegation {delegation.id}: target={target}; Foundry handles the result.") + elif nested: + delegation_id = event.get("delegation_id") + if delegation_id not in self.delegations: + raise RuntimeError("A backend event was not correlated with an observed managed delegation.") + if nested["type"] == "response.completed": + response = nested.get("response") + if not isinstance(response, Mapping) or response.get("status") != "completed": + raise RuntimeError("Malformed managed backend completion: expected status=completed.") + self.delegations[delegation_id] = True + print(f"Backend completed delegation {delegation_id}; still waiting for frontend speech.") + self.last_activity = now + elif isinstance(event, models.LiveOutputAudioDelta): + pcm = base64.b64decode(event.delta, validate=True) + if len(pcm) % 2: + raise ValueError("The service returned an incomplete PCM16 sample.") + if self.delegations: + self.audio_bytes += len(pcm) + self.audio_chunks += 1 + if _has_audio_activity(pcm): + self._audio_after_delegation = True + self.last_activity = now + elif isinstance(event, models.LiveServerEventLiveInputTranscriptDelta): + self.input_transcript += event.delta + elif isinstance(event, models.LiveServerEventLiveOutputTranscriptDelta) and self.delegations: + self.output_transcript += event.delta + if event.delta.strip(): + self._transcript_after_delegation = True + self.last_activity = now + + def ready(self, now: float) -> bool: + return ( + bool(self.delegations) + and all(self.delegations.values()) + and self._audio_after_delegation + and self._transcript_after_delegation + and now - self.last_activity >= OUTPUT_IDLE_SECONDS + ) + + +def stream_managed_audio(connection: BetaLiveConnection, pcm: bytes) -> ManagedReply: + """Interleave paced audio sends and bounded receives on the synchronous socket.""" + started = time.monotonic() + deadline = started + len(pcm) / (2 * SAMPLE_RATE) + RESPONSE_TIMEOUT + ready_after = None + next_send = started + position = 0 + output = ManagedReply(last_activity=started) + while True: + remaining_time(deadline, "managed backend completion and nonempty Live audio/transcript") + now = time.monotonic() + if ready_after is not None and now >= ready_after and output.ready(now): + return output + if now >= next_send: + chunk = pcm[position : position + CHUNK_BYTES] if position < len(pcm) else _SILENCE + connection.session.input_audio.append(audio=chunk) + position = min(position + len(chunk), len(pcm)) + next_send = time.monotonic() + len(chunk) / (2 * SAMPLE_RATE) + if ready_after is None and position == len(pcm): + ready_after = next_send + 1.0 + # Silence keeps the Live media clock advancing while Foundry runs the backend. + timeout = min(remaining_time(deadline, "managed Live events"), max(0.001, next_send - time.monotonic())) + try: + event = connection.recv(timeout=timeout) + except TimeoutError: + continue + output.observe(event, time.monotonic()) + + +async def stream_managed_audio_async(connection: AsyncBetaLiveConnection, pcm: bytes) -> ManagedReply: + """Use the same media clock and completion conditions without blocking the event loop.""" + started = time.monotonic() + deadline = started + len(pcm) / (2 * SAMPLE_RATE) + RESPONSE_TIMEOUT + ready_after = None + next_send = started + position = 0 + output = ManagedReply(last_activity=started) + while True: + remaining_time(deadline, "managed backend completion and nonempty Live audio/transcript") + now = time.monotonic() + if ready_after is not None and now >= ready_after and output.ready(now): + return output + if now >= next_send: + chunk = pcm[position : position + CHUNK_BYTES] if position < len(pcm) else _SILENCE + await asyncio.wait_for( + connection.session.input_audio.append(audio=chunk), + timeout=remaining_time(deadline, "managed Live input audio"), + ) + position = min(position + len(chunk), len(pcm)) + next_send = time.monotonic() + len(chunk) / (2 * SAMPLE_RATE) + if ready_after is None and position == len(pcm): + ready_after = next_send + 1.0 + timeout = min(remaining_time(deadline, "managed Live events"), max(0.001, next_send - time.monotonic())) + try: + event = await asyncio.wait_for(connection.recv(), timeout=timeout) + except asyncio.TimeoutError: + continue + output.observe(event, time.monotonic()) + + +def print_reply(output: ManagedReply, input_bytes: int) -> None: + safe_print(f"Input transcript: {output.input_transcript.strip() or '(not emitted by the service)'}") + safe_print(f"Output transcript: {output.output_transcript.strip()}") + print(f"Sent {input_bytes} recorded PCM16 bytes, plus paced silence while waiting.") + print(f"Received {output.audio_bytes} PCM16 bytes in {output.audio_chunks} chunks after managed delegation.") + print( + f"Frontend audio and transcript were idle for {OUTPUT_IDLE_SECONDS:g}s. " + "This is a bounded end-of-reply heuristic, not a playback-complete event; long pauses can cut off speech." + ) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/realtime_interruption_utils.py b/sdk/ai/azure-ai-projects/samples/agents/voice/realtime_interruption_utils.py new file mode 100644 index 000000000000..46aba6effb95 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/realtime_interruption_utils.py @@ -0,0 +1,302 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Shared interruption and recording helpers for the Realtime samples.""" + +from __future__ import annotations + +import array +import asyncio +import base64 +from dataclasses import dataclass +import io +import sys +import time +from typing import Any, Mapping, TYPE_CHECKING +import wave + +from azure.ai.projects import models +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError + +if TYPE_CHECKING: + from azure.ai.projects import AIProjectClient + from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient + from azure.ai.projects.operations import BetaRealtimeConnection + from azure.ai.projects.aio.operations import AsyncBetaRealtimeConnection + + +TURN_TIMEOUT = 45.0 +RECORDING_TIMEOUT = 90.0 +_MIN_AUDIO_BYTES = 9600 + + +def interruption_definition(model: str) -> models.VoiceAgentDefinition: + """Configure a stored PCM16 session without requiring audio devices.""" + return models.VoiceAgentDefinition( + model_type=models.VoiceModelType.MANAGED, + model=model, + instructions="Follow the user's request. Speak clearly and continue until interrupted.", + audio=models.VoiceAgentAudioConfig( + output=models.VoiceAgentAudioOutputConfig( + voice="en-US-AvaNeural", + voice_type=models.VoiceType.AZURE_STANDARD, + format=models.RealtimeAudioFormatsAudioPcm(rate=24000), + ) + ), + output_modalities=[models.VoiceOutputModality.AUDIO], + store=True, + ) + + +def _remaining(deadline: float, description: str) -> float: + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError(f"Timed out waiting for {description}.") + return remaining + + +@dataclass +class InterruptedTurn: + """Track one response without confusing received audio with heard audio.""" + + conversation_id: str = "" + response_id: str = "" + item_id: str = "" + stored_item_id: str = "" + received_audio_bytes: int = 0 + speech_received: bool = False + interruption_requested: bool = False + cancelled: bool = False + truncated: bool = False + + @property + def ready_to_interrupt(self) -> bool: + return ( + not self.interruption_requested + and bool(self.item_id) + and self.speech_received + and self.received_audio_bytes >= _MIN_AUDIO_BYTES + ) + + def consume(self, event: Mapping[str, Any]) -> None: + event_type = event.get("type") + if event_type == "error": + error = event.get("error") or {} + raise RuntimeError(f"Realtime interruption failed: {error.get('code')}: {error.get('message')}") + if event_type == "session.created": + self.conversation_id = event.get("conversation_id") or "" + if not self.conversation_id: + raise RuntimeError("The session did not provide a stored conversation ID.") + elif event_type == "response.created": + response = event.get("response") or {} + if not self.response_id: + self.response_id = response.get("id") or "" + if not self.response_id: + raise RuntimeError("The response did not provide an ID.") + elif ( + event_type in ("response.audio.delta", "response.output_audio.delta") + and event.get("response_id") == self.response_id + ): + item_id = event.get("item_id") + if not isinstance(item_id, str) or not item_id: + raise RuntimeError("An audio delta did not provide an item ID.") + if self.item_id and item_id != self.item_id: + raise RuntimeError("The response unexpectedly produced more than one audio item.") + self.item_id = item_id + pcm = base64.b64decode(event["delta"], validate=True) + if len(pcm) % 2: + raise ValueError("The service returned a partial PCM16 sample.") + self.received_audio_bytes += len(pcm) + self.speech_received |= any( + abs(int.from_bytes(pcm[index : index + 2], "little", signed=True)) > 256 + for index in range(0, len(pcm), 2) + ) + elif event_type == "response.done": + response = event.get("response") or {} + if response.get("id") == self.response_id: + if not self.interruption_requested or response.get("status") != "cancelled": + raise RuntimeError("The response ended without confirming the requested cancellation.") + self.cancelled = True + elif event_type == "conversation.item.truncated" and event.get("item_id") == self.item_id: + if not self.interruption_requested or event.get("audio_end_ms") != 0: + raise RuntimeError("The service did not confirm truncation to the requested playback position.") + self.truncated = True + + +_PROMPT = { + "type": "message", + "role": "user", + "content": [ + { + "type": "input_text", + "text": "Count slowly from one through fifty, saying every number aloud. Do not summarize the sequence.", + } + ], +} + + +def interrupt_reply(connection: BetaRealtimeConnection, turn: InterruptedTurn) -> None: + """Cancel a speaking response and report that none of its audio was played.""" + deadline = time.monotonic() + TURN_TIMEOUT + while not turn.conversation_id: + turn.consume(connection.recv(timeout=_remaining(deadline, "session.created"))) + connection.conversation.item.create(item=_PROMPT) + connection.response.create() + while not (turn.cancelled and turn.truncated): + turn.consume(connection.recv(timeout=_remaining(deadline, "response cancellation and item truncation"))) + if turn.ready_to_interrupt: + turn.interruption_requested = True + connection.response.cancel(response_id=turn.response_id) + # This headless example played no samples. A real player must report its actual playback position. + connection.conversation.item.truncate(item_id=turn.item_id, content_index=0, audio_end_ms=0) + + +async def interrupt_reply_async(connection: AsyncBetaRealtimeConnection, turn: InterruptedTurn) -> None: + """Asynchronously cancel a speaking response without using audio devices.""" + deadline = time.monotonic() + TURN_TIMEOUT + while not turn.conversation_id: + timeout = _remaining(deadline, "session.created") + turn.consume(await asyncio.wait_for(connection.recv(), timeout)) + await connection.conversation.item.create(item=_PROMPT) + await connection.response.create() + while not (turn.cancelled and turn.truncated): + timeout = _remaining(deadline, "response cancellation and item truncation") + turn.consume(await asyncio.wait_for(connection.recv(), timeout)) + if turn.ready_to_interrupt: + turn.interruption_requested = True + await connection.response.cancel(response_id=turn.response_id) + await connection.conversation.item.truncate(item_id=turn.item_id, content_index=0, audio_end_ms=0) + + +def validate_generated_audio(metadata: models.VoiceGeneratedAudioItem, content: bytes, turn: InterruptedTurn) -> None: + """Require a real, non-silent WAV belonging to the interrupted response.""" + if ( + metadata.conversation_id != turn.conversation_id + or not turn.stored_item_id + or metadata.item_id != turn.stored_item_id + or metadata.role != "agent" + or metadata.format != "wav" + or metadata.codec != "pcm16" + or metadata.sample_rate != 24000 + or metadata.channels != 1 + or metadata.duration_ms is None + or metadata.duration_ms.total_seconds() <= 0 + or metadata.blob_uri is not None + ): + raise ValueError("Expected Foundry-managed PCM16 generated audio for the interrupted item.") + if content[:4] != b"RIFF" or content[8:12] != b"WAVE": + raise ValueError("The generated audio download is not a WAV file.") + with wave.open(io.BytesIO(content), "rb") as recording: + frames = recording.getnframes() + pcm = recording.readframes(frames) + if ( + recording.getcomptype() != "NONE" + or recording.getsampwidth() != 2 + or recording.getframerate() != metadata.sample_rate + or recording.getnchannels() != metadata.channels + or frames <= 0 + or len(pcm) != frames * 2 + or abs(frames / metadata.sample_rate - metadata.duration_ms.total_seconds()) > 0.01 + ): + raise ValueError("The generated WAV does not match its audio metadata.") + samples = array.array("h", pcm) + if sys.byteorder != "little": + samples.byteswap() + if not any(abs(sample) > 256 for sample in samples): + raise ValueError("The generated recording contains no non-silent agent speech.") + + +def _recording_pending(exc: HttpResponseError) -> bool: + return isinstance(exc, ResourceNotFoundError) or ( + exc.status_code == 409 and getattr(exc.error, "code", None) == "recording_not_ready" + ) + + +def _stored_audio_item(items: list[Mapping[str, Any]], response_id: str) -> str | None: + candidates = [ + item + for item in items + if item.get("type") == "message" and item.get("role") == "assistant" and item.get("response_id") == response_id + ] + if not candidates: + return None + if len(candidates) != 1: + raise RuntimeError("The interrupted response did not map to exactly one stored assistant item.") + identifier = candidates[0].get("id") + if not isinstance(identifier, str) or not identifier: + raise RuntimeError("The stored assistant item did not provide its REST resource ID.") + return identifier + + +def wait_for_generated_audio( + client: AIProjectClient, agent_name: str, turn: InterruptedTurn +) -> tuple[models.VoiceGeneratedAudioItem, bytes]: + """Wait for durable interruption artifacts before reading them once in a test.""" + deadline = time.monotonic() + RECORDING_TIMEOUT + conversations = client.beta.voice_agents.conversations + while time.monotonic() < deadline: + try: + conversation = conversations.get(agent_name, turn.conversation_id) + if conversation.status == "failed": + raise RuntimeError("The interrupted conversation failed to persist.") + if conversation.status == "completed": + # Persisted REST item IDs differ from the native WebSocket item IDs. + stored_item_id = _stored_audio_item( + list(conversations.list_items(agent_name, turn.conversation_id)), turn.response_id + ) + if stored_item_id is not None: + turn.stored_item_id = stored_item_id + metadata = conversations.get_generated_audio_item( + agent_name, turn.conversation_id, turn.stored_item_id + ) + content = b"".join( + conversations.download_generated_audio_item( + agent_name, turn.conversation_id, turn.stored_item_id + ) + ) + validate_generated_audio(metadata, content, turn) + return metadata, content + except HttpResponseError as exc: + if not _recording_pending(exc): + raise + time.sleep(min(1.0, _remaining(deadline, "stored generated audio"))) + raise TimeoutError("The interrupted response did not produce persisted generated audio before the deadline.") + + +async def wait_for_generated_audio_async( + client: AsyncAIProjectClient, agent_name: str, turn: InterruptedTurn +) -> tuple[models.VoiceGeneratedAudioItem, bytes]: + """Wait asynchronously for durable generated audio; never treat a 404 as success.""" + deadline = time.monotonic() + RECORDING_TIMEOUT + conversations = client.beta.voice_agents.conversations + while time.monotonic() < deadline: + try: + conversation = await conversations.get(agent_name, turn.conversation_id) + if conversation.status == "failed": + raise RuntimeError("The interrupted conversation failed to persist.") + if conversation.status == "completed": + stored_item_id = _stored_audio_item( + [item async for item in conversations.list_items(agent_name, turn.conversation_id)], + turn.response_id, + ) + if stored_item_id is not None: + turn.stored_item_id = stored_item_id + metadata = await conversations.get_generated_audio_item( + agent_name, turn.conversation_id, turn.stored_item_id + ) + content = b"".join( + [ + chunk + async for chunk in await conversations.download_generated_audio_item( + agent_name, turn.conversation_id, turn.stored_item_id + ) + ] + ) + validate_generated_audio(metadata, content, turn) + return metadata, content + except HttpResponseError as exc: + if not _recording_pending(exc): + raise + await asyncio.sleep(min(1.0, _remaining(deadline, "stored generated audio"))) + raise TimeoutError("The interrupted response did not produce persisted generated audio before the deadline.") diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic.py index 590a313c1b90..bccc87c9260a 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic.py @@ -6,28 +6,20 @@ """ DESCRIPTION: - This sample demonstrates the voice-agent management lifecycle using the - synchronous AIProjectClient: creating a voice agent, retrieving it, - listing the voice agents in the project, and deleting it. - - Voice agents are exposed through `project_client.agents` with - `kind="voice"`, the same surface used for prompt, workflow, hosted, and - external agents. + Create a voice agent, read its settings, add a version, and list voice + agents in the project. Delete the versions created by this sample. + Voice agents use project_client.agents with kind="voice". USAGE: python sample_voice_agent_basic.py - Before running the sample: - pip install "azure-ai-projects>=2.7.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_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". - 3) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of the voice agent. If not - set, defaults to "MyVoiceAgent". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (optional) - Managed Realtime model; + defaults to "gpt-realtime". + 3) FOUNDRY_VOICE_AGENT_NAME (optional) - Agent name; defaults to "MyVoiceAgent". """ import os diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic_async.py deleted file mode 100644 index ef63f207e1c0..000000000000 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic_async.py +++ /dev/null @@ -1,75 +0,0 @@ -# pylint: disable=line-too-long,useless-suppression -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ - -""" -DESCRIPTION: - This sample demonstrates the voice-agent management lifecycle using the - asynchronous AIProjectClient: creating a voice agent, retrieving it, - listing the voice agents in the project, and deleting it. - -USAGE: - python sample_voice_agent_basic_async.py - - Before running the sample: - - pip install "azure-ai-projects>=2.7.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_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". - 3) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of the voice agent. If not - set, defaults to "MyVoiceAgentAsync". -""" - -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 AgentKind, VoiceAgentDefinition, VoiceModelType - -load_dotenv() - - -async def main() -> None: - endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] - model = os.environ.get("FOUNDRY_VOICE_AGENT_MODEL") or "gpt-realtime" - agent_name = os.environ.get("FOUNDRY_VOICE_AGENT_NAME") or "MyVoiceAgentAsync" - - async with ( - DefaultAzureCredential() as credential, - AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, - ): - created_version = None - try: - created_version = await project_client.agents.create_version( - agent_name=agent_name, - definition=VoiceAgentDefinition( - model_type=VoiceModelType.MANAGED, - model=model, - instructions="You are a friendly voice assistant. Keep replies short and natural.", - # Persist conversations so they can be read back later. Defaults to False. - store=True, - ), - ) - print(f"Created voice agent '{agent_name}', version: {created_version.version}") - - agent = await project_client.agents.get(agent_name=agent_name) - print(f"Retrieved voice agent: {agent.name}") - - print("Voice agents in this project:") - async for item in project_client.agents.list(kind=AgentKind.VOICE): - print(f" - {item.name}") - finally: - if created_version is not None: - await project_client.agents.delete_version(agent_name=agent_name, agent_version=created_version.version) - print(f"Deleted voice agent version: {created_version.version}") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py index 7b42328d5490..f34c39b7f1db 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py @@ -6,22 +6,19 @@ """ DESCRIPTION: - This sample demonstrates guided authoring: generating and creating a voice - agent through `create_from_prompt` with `kind="voice"`. - The service creates a voice agent with a service-selected starter definition, - which is fully editable afterward through the standard create_version/update flow. + Describe the voice agent you want and create it with create_from_prompt. + The service chooses initial settings. You can later customize them by + creating another agent version. USAGE: python sample_voice_agent_generate.py - Before running the sample: - pip install "azure-ai-projects>=2.7.0" python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. - 2) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of the voice agent. If not - set, defaults to "MyGeneratedVoiceAgent". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_NAME (optional) - Agent name; + defaults to "MyGeneratedVoiceAgent". """ import os @@ -35,14 +32,7 @@ def _safe_print(text: str) -> None: - """Print text that may contain characters the current console can't display. - - The instructions below are model-generated and can contain characters (curly - quotes, em-dashes, etc.) outside some legacy, non-Unicode console encodings - (for example when stdout is piped/redirected on Windows). Rather than crashing - with UnicodeEncodeError, fall back to replacing just the unsupported characters; - a real interactive UTF-8 console prints unaffected. - """ + """Print model text, replacing characters the console cannot display.""" try: print(text) except UnicodeEncodeError: diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py new file mode 100644 index 000000000000..7cf287ecff31 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py @@ -0,0 +1,498 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Send the bundled spoken question to GPT Live and print the reply transcript + and audio size. The sample deletes its temporary agent version afterward. + +USAGE: + python sample_voice_agent_live_audio_conversation_async.py + + Settings in this file: + - USE_MICROPHONE = False (default): send audio/question.wav; no devices needed. + - USE_MICROPHONE = True: use a microphone and speakers. Use headphones + to avoid feedback; press Ctrl-C to stop. + - SAVE_AUDIO = True: save reply audio in a printed temporary folder. + These files contain conversation content; remove them when finished. + + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + pip install pyaudio # Only required for microphone mode. + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required) - Your GPT Live deployment name. + 3) FOUNDRY_VOICE_AUDIO_INPUT_PATH (optional) - Override audio/question.wav + with your own uncompressed PCM16, mono, 24-kHz WAV. + 4) FOUNDRY_VOICE_AGENT_NAME (optional) - Prefix for the temporary agent name. + + Uses DefaultAzureCredential. Capture ends after three quiet seconds; + a long pause can cut off a reply. Audio is not saved by default. +""" + +from __future__ import annotations + +import asyncio +import base64 +import concurrent.futures +from contextlib import ExitStack +from dataclasses import dataclass +import os +from pathlib import Path +import queue +from tempfile import mkdtemp +import time +from typing import Any, Optional, TYPE_CHECKING +import wave + +from dotenv import load_dotenv +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects import models + +from live_sample_utils import ( + audio_settings, + check_event, + check_session_open, + close_session_async, + input_audio_path, + remaining_time, + safe_print, + sample_agent_name, + wait_for_event_async, +) + +if TYPE_CHECKING: + from azure.ai.projects.aio.operations import AsyncBetaLiveConnection + + +USE_MICROPHONE = False +SAVE_AUDIO = False + +_SAMPLE_RATE = 24000 +_CHUNK_FRAMES = 1200 +_OUTPUT_IDLE_SECONDS = 3.0 +_SILENCE_PEAK_THRESHOLD = 256 + + +@dataclass +class _AudioOutput: + num_bytes: int = 0 + chunks: int = 0 + input_transcript: str = "" + output_transcript: str = "" + has_audio_activity: bool = False + + +def _microphone_backend() -> Any: + try: + import pyaudio + except ImportError as exc: + raise RuntimeError("Microphone mode requires PyAudio. Install it with: pip install pyaudio") from exc + return pyaudio + + +class _MicrophoneAudio: + """Bounded, nonblocking microphone capture and PCM speaker playback.""" + + def __init__(self, connection: AsyncBetaLiveConnection, backend: Any) -> None: + self._connection = connection + self._backend = backend + self._audio = backend.PyAudio() + self._loop: Optional[asyncio.AbstractEventLoop] = None + self._input_stream: Any = None + self._output_stream: Any = None + self._pending_send: Optional[concurrent.futures.Future[None]] = None + self._capture_error: Optional[BaseException] = None + self._capture_active = False + self._playback_queue: queue.Queue[bytes] = queue.Queue(maxsize=200) + self._playback_remaining = b"" + self.input_bytes = 0 + self.output_bytes = 0 + self.dropped_frames = 0 + + async def _append_input_audio(self, pcm: bytes) -> None: + await self._connection.session.input_audio.append(audio=pcm) + self.input_bytes += len(pcm) + + def _capture_callback(self, pcm: bytes, _frame_count: int, _time_info: Any, status: int) -> tuple[None, int]: + if not self._capture_active: + return None, self._backend.paAbort + if status: + self._capture_error = RuntimeError(f"Microphone callback reported audio status {status}.") + return None, self._backend.paAbort + if self._pending_send is not None: + if not self._pending_send.done(): + self.dropped_frames += 1 + return None, self._backend.paContinue + if self._pending_send.cancelled(): + self._capture_error = RuntimeError("The microphone audio send was cancelled.") + return None, self._backend.paAbort + failure = self._pending_send.exception() + if failure is not None: + self._capture_error = failure + return None, self._backend.paAbort + assert self._loop is not None + self._pending_send = asyncio.run_coroutine_threadsafe(self._append_input_audio(pcm), self._loop) + return None, self._backend.paContinue + + def _playback_callback(self, _pcm: Any, frame_count: int, _time_info: Any, status: int) -> tuple[bytes, int]: + wanted = frame_count * 2 + if status: + self._capture_error = RuntimeError(f"Speaker callback reported audio status {status}.") + return bytes(wanted), self._backend.paAbort + output = self._playback_remaining[:wanted] + self._playback_remaining = self._playback_remaining[wanted:] + while len(output) < wanted: + try: + chunk = self._playback_queue.get_nowait() + except queue.Empty: + output += bytes(wanted - len(output)) + break + take = wanted - len(output) + output += chunk[:take] + self._playback_remaining = chunk[take:] + return output, self._backend.paContinue + + def start(self) -> None: + audio = self._audio + if audio is None: + raise RuntimeError("Cannot restart closed microphone audio devices.") + self._loop = asyncio.get_running_loop() + self._output_stream = audio.open( + format=self._backend.paInt16, + channels=1, + rate=_SAMPLE_RATE, + output=True, + frames_per_buffer=_CHUNK_FRAMES, + stream_callback=self._playback_callback, + start=False, + ) + self._input_stream = audio.open( + format=self._backend.paInt16, + channels=1, + rate=_SAMPLE_RATE, + input=True, + frames_per_buffer=_CHUNK_FRAMES, + stream_callback=self._capture_callback, + start=False, + ) + self._capture_active = True + self._output_stream.start_stream() + self._input_stream.start_stream() + + def check_capture_error(self) -> None: + if self._capture_error is not None: + raise self._capture_error + if self._pending_send is not None and self._pending_send.done(): + self._pending_send.result() + + def enqueue_audio(self, pcm: bytes) -> None: + if len(pcm) % 2: + raise ValueError("The service returned an incomplete PCM16 sample.") + self.output_bytes += len(pcm) + try: + self._playback_queue.put_nowait(pcm) + except queue.Full as exc: + raise RuntimeError("Speaker playback fell behind; the audio buffer is full.") from exc + + async def stop(self) -> None: + self._capture_active = False + try: + try: + if self._input_stream is not None: + stream, self._input_stream = self._input_stream, None + try: + stream.stop_stream() + finally: + stream.close() + finally: + if self._pending_send is not None: + pending, self._pending_send = self._pending_send, None + if pending.cancelled(): + raise RuntimeError("The microphone audio send was cancelled.") + await asyncio.wrap_future(pending) + finally: + try: + if self._output_stream is not None: + stream, self._output_stream = self._output_stream, None + try: + stream.stop_stream() + finally: + stream.close() + finally: + if self._audio is not None: + audio, self._audio = self._audio, None + audio.terminate() + + +async def _stream_microphone( + connection: AsyncBetaLiveConnection, backend: Any, output_file: Optional[wave.Wave_write] +) -> bool: + audio = _MicrophoneAudio(connection, backend) + last_role = "" + try: + audio.start() + print("Speak now -- GPT Live replies through your speakers. Use headphones to avoid feedback.") + print("Press Ctrl-C to stop the microphone, close the session, and clean up.") + while True: + audio.check_capture_error() + try: + event = await asyncio.wait_for(connection.recv(), timeout=0.5) + except asyncio.TimeoutError: + continue + check_event(event) + if event.get("type") == "session.closed": + reason = event.get("reason") + if reason not in ("close_requested", "expired", "remote_hangup"): + raise RuntimeError(f"Live session ended unexpectedly: {reason}") + print(f"\nSession closed: {reason}") + return True + if isinstance(event, models.LiveOutputAudioDelta): + pcm = base64.b64decode(event.delta, validate=True) + audio.enqueue_audio(pcm) + if output_file is not None: + output_file.writeframesraw(pcm) + elif isinstance( + event, (models.LiveServerEventLiveInputTranscriptDelta, models.LiveServerEventLiveOutputTranscriptDelta) + ): + role = "You" if isinstance(event, models.LiveServerEventLiveInputTranscriptDelta) else "Agent" + if role != last_role: + safe_print(f"\n{role}: ", end="") + last_role = role + safe_print(event.delta, end="") + elif isinstance(event, models.LiveServerEventLiveDelegationCreated): + if event.delegation.target == "client": + await connection.session.commentary.append( + content="This sample cannot look up external information. Briefly acknowledge the spoken request.", + delegation_id=event.delegation.id, + ) + finally: + try: + await audio.stop() + finally: + print( + f"\nInput audio: {audio.input_bytes} bytes ({audio.input_bytes / 1048576:.2f} MiB), " + f"PCM16, 24000 Hz, mono, {audio.input_bytes / 48000:.2f}s." + ) + print( + f"Output audio: {audio.output_bytes} bytes ({audio.output_bytes / 1048576:.2f} MiB), " + f"PCM16, 24000 Hz, mono, {audio.output_bytes / 48000:.2f}s." + ) + print(f"Total audio transferred: {audio.input_bytes + audio.output_bytes} bytes.") + if audio.dropped_frames: + print(f"Dropped {audio.dropped_frames} microphone frame(s) while a previous send was in flight.") + + +def _has_audio_activity(pcm: bytes) -> bool: + return any( + abs(int.from_bytes(pcm[offset : offset + 2], "little", signed=True)) > _SILENCE_PEAK_THRESHOLD + for offset in range(0, len(pcm), 2) + ) + + +def _validate_recording(recording: wave.Wave_read) -> None: + if ( + recording.getnchannels() != 1 + or recording.getsampwidth() != 2 + or recording.getframerate() != _SAMPLE_RATE + or recording.getcomptype() != "NONE" + ): + raise ValueError("FOUNDRY_VOICE_AUDIO_INPUT_PATH must be an uncompressed PCM16, mono, 24000 Hz WAV file.") + if recording.getnframes() == 0: + raise ValueError("The input WAV contains no audio frames.") + + +async def _send_audio(connection: AsyncBetaLiveConnection, recording: wave.Wave_read, finished: asyncio.Event) -> int: + num_bytes = 0 + while chunk := recording.readframes(_CHUNK_FRAMES): + await connection.session.input_audio.append(audio=chunk) + num_bytes += len(chunk) + await asyncio.sleep(len(chunk) / (2 * _SAMPLE_RATE)) + if num_bytes == 0: + raise RuntimeError("No recorded audio frames were sent.") + # Trailing silence lets the model finish the recorded speech turn. + for _ in range(_SAMPLE_RATE // _CHUNK_FRAMES): + silence = b"\x00\x00" * _CHUNK_FRAMES + await connection.session.input_audio.append(audio=silence) + num_bytes += len(silence) + await asyncio.sleep(_CHUNK_FRAMES / _SAMPLE_RATE) + finished.set() + return num_bytes + + +async def _receive_audio( + connection: AsyncBetaLiveConnection, + finished: asyncio.Event, + timeout: float, + output_file: Optional[wave.Wave_write], +) -> _AudioOutput: + output = _AudioOutput() + deadline = time.monotonic() + timeout + last_content = time.monotonic() + while True: + if finished.is_set() and output.has_audio_activity and time.monotonic() - last_content >= _OUTPUT_IDLE_SECONDS: + return output + remaining = remaining_time(deadline, "GPT Live reply audio") + try: + event = await asyncio.wait_for(connection.recv(), timeout=min(remaining, 1.0)) + except asyncio.TimeoutError: + continue + check_event(event) + check_session_open(event) + if isinstance(event, models.LiveOutputAudioDelta): + pcm = base64.b64decode(event.delta, validate=True) + if len(pcm) % 2: + raise ValueError("The service returned an incomplete PCM16 sample.") + output.num_bytes += len(pcm) + output.chunks += 1 + if output_file is not None: + output_file.writeframesraw(pcm) + if _has_audio_activity(pcm): + output.has_audio_activity = True + last_content = time.monotonic() + elif isinstance(event, models.LiveServerEventLiveInputTranscriptDelta): + output.input_transcript += event.delta + elif isinstance(event, models.LiveServerEventLiveOutputTranscriptDelta): + output.output_transcript += event.delta + if event.delta.strip(): + last_content = time.monotonic() + elif isinstance(event, models.LiveServerEventLiveDelegationCreated): + if event.delegation.target == "client": + await connection.session.commentary.append( + content="This sample cannot look up external information. Briefly acknowledge the recorded request.", + delegation_id=event.delegation.id, + ) + print("Replied to a client-owned delegation with associated commentary.") + + +async def _stream_recording( + connection: AsyncBetaLiveConnection, recording: wave.Wave_read, output_file: Optional[wave.Wave_write] +) -> None: + finished = asyncio.Event() + timeout = recording.getnframes() / _SAMPLE_RATE + 60 + sender = asyncio.create_task(_send_audio(connection, recording, finished)) + receiver = asyncio.create_task(_receive_audio(connection, finished, timeout, output_file)) + try: + input_bytes, output = await asyncio.wait_for(asyncio.gather(sender, receiver), timeout=timeout) + except asyncio.TimeoutError as exc: + raise TimeoutError("Timed out streaming the recording or waiting for nonempty GPT Live reply audio.") from exc + finally: + # Live has no response.cancel. Cancel local work and then request session.close. + for task in (sender, receiver): + if not task.done(): + task.cancel() + await asyncio.gather(sender, receiver, return_exceptions=True) + if input_bytes <= 0 or output.num_bytes <= 0 or not output.has_audio_activity: + raise RuntimeError("A successful conversation requires nonzero input and non-silent reply audio.") + for label, transcript in (("Input", output.input_transcript), ("Output", output.output_transcript)): + if transcript and not transcript.strip(): + raise RuntimeError(f"{label} transcript events contained no usable text.") + safe_print(f"{label} transcript: {transcript.strip() or '(not emitted by the service)'}") + print(f"Sent {input_bytes} PCM16 bytes, including 48000 bytes of trailing silence.") + print(f"Received {output.num_bytes} PCM16 bytes in {output.chunks} chunks ({output.num_bytes / 48000:.2f}s).") + + +async def _run_audio_conversation( + project_client: AIProjectClient, + agent_name: str, + agent_version: str, + recording: Optional[wave.Wave_read], + output_file: Optional[wave.Wave_write], + *, + audio_backend: Any = None, +) -> None: + if recording is None and audio_backend is None: + raise ValueError("Microphone mode requires an audio backend.") + session_closed = False + cancelled = False + async with project_client.beta.voice_agents.live.connect( + agent_name=agent_name, agent_version=agent_version, store=False + ) as connection: + try: + await wait_for_event_async(connection, "session.started") + if recording is None: + try: + session_closed = await _stream_microphone(connection, audio_backend, output_file) + except asyncio.CancelledError: + print("\n(ending microphone conversation...)") + cancelled = True + else: + print("Live session started; sending the recording and receiving audio concurrently.") + await _stream_recording(connection, recording, output_file) + finally: + if not session_closed: + await close_session_async(connection) + if cancelled: + raise asyncio.CancelledError + + +async def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"] + backend = _microphone_backend() if USE_MICROPHONE else None + input_path = None if USE_MICROPHONE else input_audio_path() + output_path: Optional[Path] = None + agent_name = sample_agent_name("audio") + + with ExitStack() as files: + recording = files.enter_context(wave.open(str(input_path), "rb")) if input_path is not None else None + if recording is not None: + _validate_recording(recording) + output_file: Optional[wave.Wave_write] = None + if SAVE_AUDIO: + output_directory = Path(mkdtemp(prefix="voice-agent-live-audio-")) + output_path = output_directory / "reply.wav" + print(f"Audio output directory: {output_directory}") + output_stream = files.enter_context(output_path.open("xb")) + output_file = files.enter_context(wave.open(output_stream, "wb")) + output_file.setnchannels(1) + output_file.setsampwidth(2) + output_file.setframerate(_SAMPLE_RATE) + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + created_version = None + try: + created_version = await project_client.agents.create_version( + agent_name=agent_name, + definition=models.VoiceAgentLiveDefinition( + model=model, + model_type=models.VoiceModelType.SELF_DEPLOYED, + instructions=( + "You are a friendly voice assistant. Briefly answer the user's speech. " + "Keep replies to one short sentence. Delegate external lookups to the client." + ), + audio=audio_settings(), + delegation=models.VoiceAgentLiveClientDelegation(), + store=False, + ), + ) + if USE_MICROPHONE: + await _run_audio_conversation( + project_client, agent_name, created_version.version, None, output_file, audio_backend=backend + ) + else: + await _run_audio_conversation( + project_client, agent_name, created_version.version, recording, output_file + ) + finally: + if created_version is not None: + await project_client.agents.delete_version( + agent_name=agent_name, agent_version=created_version.version + ) + print(f"Deleted sample agent version: {created_version.version}") + if output_path: + print(f"Saved actual returned PCM16 WAV audio: {output_path} (not telemetry).") + + +if __name__ == "__main__": + try: + asyncio.run(main()) + except KeyboardInterrupt: + print("\nStopped.") diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_connection_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_connection_async.py new file mode 100644 index 000000000000..9cf9ff641fb8 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_connection_async.py @@ -0,0 +1,94 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Create a temporary GPT Live agent, open a session, update its settings, + add instructions, and close it. The sample deletes the agent version it + creates. No user input or audio devices are needed. Silent audio frames + advance the Live timeline while it acknowledges the appended instructions. + +USAGE: + python sample_voice_agent_live_connection_async.py + + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required) - Your GPT Live deployment name. + 3) FOUNDRY_VOICE_AGENT_NAME (optional) - Prefix for the temporary agent name. + + Uses DefaultAzureCredential. Foundry starts the session automatically; + wait for session.started rather than sending session.start. +""" + +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 import models + +from live_sample_utils import ( + audio_settings, + close_session_async, + sample_agent_name, + wait_for_event_async, + wait_for_event_with_audio_clock_async, +) + + +async def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"] + agent_name = sample_agent_name("connection") + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + created_version = None + try: + created_version = await project_client.agents.create_version( + agent_name=agent_name, + definition=models.VoiceAgentLiveDefinition( + model=model, + model_type=models.VoiceModelType.SELF_DEPLOYED, + instructions="You are a concise, friendly voice assistant.", + audio=audio_settings(), + delegation=models.VoiceAgentLiveClientDelegation(), + store=False, + ), + ) + async with project_client.beta.voice_agents.live.connect( + agent_name=agent_name, agent_version=created_version.version, store=False + ) as connection: + try: + started = await wait_for_event_async(connection, "session.started") + print(f"Live session started: {started['session']['id']}") + await connection.session.update( + session=models.LiveSessionUpdateParams( + delegation=models.LiveSessionUpdateParamsDelegationLiveClientDelegationParam() + ) + ) + await wait_for_event_async(connection, "session.updated") + await connection.session.instructions.append( + content="Keep responses brief. Do not invent external facts.", delegation_id=None + ) + await wait_for_event_with_audio_clock_async(connection, "session.instructions.appended") + print("Confirmed session.updated and session.instructions.appended.") + finally: + # session.close is a command; leaving the context closes the transport. + await close_session_async(connection) + finally: + if created_version is not None: + await project_client.agents.delete_version(agent_name=agent_name, agent_version=created_version.version) + print(f"Deleted sample agent version: {created_version.version}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool_async.py new file mode 100644 index 000000000000..970e4d596fb8 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool_async.py @@ -0,0 +1,162 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Let GPT Live call a local weather function, return its result, and print + the final reply. Weather is fixed sample data, not a live forecast. + The sample deletes its temporary agent version when finished. + +USAGE: + python sample_voice_agent_live_function_tool_async.py + + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required) - Your GPT Live deployment name. + 3) FOUNDRY_MODEL_NAME (required) - A tool-capable Responses deployment available to Live. + 4) FOUNDRY_VOICE_AGENT_NAME (optional) - Prefix for the temporary agent name. + + Uses DefaultAzureCredential. No audio devices are needed. + Printed text does not mean voice playback has finished. +""" + +from __future__ import annotations + +import asyncio +import json +import os +import time +from typing import Any, Mapping + +from dotenv import load_dotenv +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects import models + +from live_sample_utils import ( + audio_settings, + close_session_async, + receive_response_async, + remaining_time, + safe_print, + sample_agent_name, + wait_for_event_async, +) + + +def get_weather(city: str) -> str: + """Return deterministic sample weather, rather than calling an external service.""" + if city.strip().casefold() != "seattle": + raise ValueError("This sample only provides weather data for Seattle.") + return json.dumps({"city": "Seattle", "condition": "sunny", "temperature_f": 72}) + + +def _execute_tool(call: Mapping[str, Any]) -> str: + if call.get("name") != "get_weather": + raise RuntimeError(f"Unexpected backend function: {call.get('name')}") + arguments = json.loads(call["arguments"]) + if not isinstance(arguments, dict) or set(arguments) != {"city"} or not isinstance(arguments["city"], str): + raise ValueError("get_weather requires exactly one string argument named city.") + return get_weather(arguments["city"]) + + +async def _run_tool_turn(project_client: AIProjectClient, agent_name: str, agent_version: str) -> str: + async with project_client.beta.voice_agents.live.connect( + agent_name=agent_name, agent_version=agent_version, store=False + ) as connection: + try: + await wait_for_event_async(connection, "session.started") + await connection.response.item.create( + item={ + "type": "message", + "role": "user", + "content": [ + {"type": "input_text", "text": "Use get_weather for Seattle, then report the sample result."} + ], + } + ) + await connection.response.create() + deadline = time.monotonic() + 120 + handled_calls: set[str] = set() + for _ in range(6): + text, calls = await receive_response_async( + connection, timeout=remaining_time(deadline, "the tool-backed answer") + ) + if not calls: + if not handled_calls: + raise RuntimeError("The backend answered without calling get_weather.") + if not text: + raise RuntimeError("The backend completed without returning an answer.") + return text + # Complete the backend cycle before submitting results or starting another response. + for call in calls: + call_id = call["call_id"] + if not call_id or call_id in handled_calls: + raise RuntimeError("The backend returned a missing or repeated function call ID.") + result = _execute_tool(call) + await connection.response.item.create( + item={"type": "function_call_output", "call_id": call_id, "output": result} + ) + handled_calls.add(call_id) + print("get_weather returned sample data: Seattle, sunny, 72 F.") + await connection.response.create() + raise RuntimeError("The backend exceeded this sample's six-response tool-call limit.") + finally: + await close_session_async(connection) + + +async def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"] + backend_model = os.environ["FOUNDRY_MODEL_NAME"] + agent_name = sample_agent_name("function-tool") + + weather_tool = models.LiveFunctionToolInputParam( + name="get_weather", + description="Return sample weather for Seattle, not a live forecast.", + parameters={ + "type": "object", + "properties": {"city": {"type": "string", "enum": ["Seattle"]}}, + "required": ["city"], + "additionalProperties": False, + }, + strict=True, + ) + definition = models.VoiceAgentLiveDefinition( + model=model, + model_type=models.VoiceModelType.SELF_DEPLOYED, + instructions="Delegate weather questions to the Responses backend.", + audio=audio_settings(), + delegation=models.VoiceAgentLiveResponsesDelegation( + responses=models.LiveResponsesDelegationSettingsInputParam( + model=backend_model, + instructions=( + "Call get_weather for Seattle, then answer once using its result. " + "Do not call it again. Label the result as sample weather." + ), + tools=[weather_tool], + parallel_tool_calls=False, + ) + ), + store=False, + ) + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + agent = await project_client.agents.create_version(agent_name=agent_name, definition=definition) + try: + answer = await _run_tool_turn(project_client, agent_name, agent.version) + safe_print(f"Responses backend: {answer}") + finally: + await project_client.agents.delete_version(agent_name=agent_name, agent_version=agent.version) + print(f"Deleted sample agent version: {agent.version}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_managed_agent_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_managed_agent_async.py new file mode 100644 index 000000000000..d916299820c7 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_managed_agent_async.py @@ -0,0 +1,96 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Ask a same-project prompt agent a spoken question through GPT Live. + Send the bundled spoken question, print the reply transcript and audio size, and delete + both temporary agent versions. No microphone or speakers are needed. + +USAGE: + python sample_voice_agent_live_managed_agent_async.py + + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required) - An existing GPT Live deployment. + 3) FOUNDRY_MODEL_NAME (required) - A prompt-agent deployment in the same project. + 4) FOUNDRY_VOICE_AUDIO_INPUT_PATH (optional) - Override audio/question.wav + with your own PCM16, mono, 24-kHz WAV of at most 30 seconds. + 5) FOUNDRY_VOICE_AGENT_NAME (optional) - Prefix for unique owned names. + + Uses DefaultAzureCredential. Foundry runs the backend; the client only + streams audio. Reply audio is counted, not played or saved. Capture ends + after three quiet seconds; a long pause can cut off a reply. +""" + +from __future__ import annotations + +import asyncio +from contextlib import AsyncExitStack +import os + +from dotenv import load_dotenv +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects import models + +from live_sample_utils import close_session_async, input_audio_path, sample_agent_name, wait_for_event_async +from managed_agent_sample_utils import ( + PROMPT_INSTRUCTIONS, + check_managed_session, + live_definition, + print_reply, + read_input_audio, + stream_managed_audio_async, +) + + +async def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"] + backend_model = os.environ["FOUNDRY_MODEL_NAME"] + pcm = read_input_audio(input_audio_path()) + backend_name = sample_agent_name("managed-backend") + voice_name = sample_agent_name("managed-frontend") + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + AsyncExitStack() as cleanup, + ): + backend = await project_client.agents.create_version( + agent_name=backend_name, + definition=models.PromptAgentDefinition(model=backend_model, instructions=PROMPT_INSTRUCTIONS), + ) + cleanup.push_async_callback( + project_client.agents.delete_version, agent_name=backend_name, agent_version=backend.version + ) + voice = await project_client.agents.create_version( + agent_name=voice_name, definition=live_definition(model, backend_name, backend.version) + ) + cleanup.push_async_callback( + project_client.agents.delete_version, agent_name=voice_name, agent_version=voice.version + ) + + async with project_client.beta.voice_agents.live.connect( + agent_name=voice_name, agent_version=voice.version, store=False + ) as connection: + try: + started = await wait_for_event_async(connection, "session.started") + if not isinstance(started, models.LiveServerEventLiveSessionStarted): + raise RuntimeError("Expected a typed session.started event from the Live handshake.") + check_managed_session(started.session, backend_name, backend.version) + output = await stream_managed_audio_async(connection, pcm) + finally: + await close_session_async(connection) + print_reply(output, len(pcm)) + print("Deleted only the Live and prompt-agent versions created by this run.") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_read_conversation.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_read_conversation.py new file mode 100644 index 000000000000..403b7e2fba6a --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_read_conversation.py @@ -0,0 +1,292 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Read a GPT Live conversation, list its items, and download its audio using + project_client.beta.voice_agents.live_conversations. + + With no conversation ID, the sample creates a short greeting session and + deletes its conversation and temporary agent version afterward. No microphone, + input WAV, or Responses model is needed. Supplying an existing ID skips + creation and leaves the existing agent and conversation untouched. + + WAV downloads remain in a unique user-temporary folder. The sample prints + its path; remove the folder when finished. Files contain conversation + content, not telemetry. BYOS audio requires your own storage credentials + and is not downloaded. + +USAGE: + python sample_voice_agent_live_read_conversation.py + + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required when creating a conversation) - + Your GPT Live deployment name. + 3) FOUNDRY_VOICE_CONVERSATION_ID (optional) - An existing conversation ID. + Unset or blank means create a conversation for this run. + 4) FOUNDRY_VOICE_AGENT_NAME - Required with an existing ID; otherwise an + optional prefix for the temporary agent name. + + Uses DefaultAzureCredential. An existing conversation needs no model + deployment or WebSocket. Use session.started.conversation_id, not session.id, + from a completed speech session with store=True. The service must support + Live REST routes; HTTP errors are raised without a Realtime fallback. +""" + +from __future__ import annotations + +import base64 +from contextlib import contextmanager, ExitStack +from itertools import islice +import os +from pathlib import Path +import struct +from tempfile import mkdtemp +import time +from typing import Iterator + +from dotenv import load_dotenv +from live_sample_utils import ( + audio_settings, + check_event, + check_session_open, + close_session, + recording_output, + remaining_time, + safe_print, + sample_agent_name, + wait_for_event, +) + +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.identity import DefaultAzureCredential +from azure.ai.projects import AIProjectClient, models +from azure.ai.projects.operations import BetaLiveConnection, BetaVoiceAgentsLiveConversationsOperations + +_SESSION_TIMEOUT = 45.0 +_FINALIZATION_TIMEOUT = 90.0 + + +def _receive_greeting(connection: BetaLiveConnection) -> None: + deadline = time.monotonic() + _SESSION_TIMEOUT + next_input = time.monotonic() + last_content = next_input + speech_received = False + input_bytes = output_bytes = 0 + while True: + remaining = remaining_time(deadline, "the sample greeting audio") + now = time.monotonic() + if speech_received and now - last_content >= 2: + print(f"Greeting audio: sent {input_bytes} silence bytes; received {output_bytes} PCM16 bytes.") + return + if now >= next_input: + connection.session.input_audio.append(audio=bytes(2400)) + input_bytes += 2400 + next_input = now + 0.05 + try: + event = connection.recv(timeout=min(remaining, max(0.001, next_input - time.monotonic()))) + except TimeoutError: + continue + check_event(event) + check_session_open(event) + if isinstance(event, models.LiveOutputAudioDelta): + pcm = base64.b64decode(event.delta, validate=True) + if len(pcm) % 2: + raise ValueError("The service returned an incomplete PCM16 sample.") + output_bytes += len(pcm) + if any(abs(sample) > 256 for (sample,) in struct.iter_unpack(" None: + print("Waiting for the sample conversation and audio to finish persisting.") + deadline = time.monotonic() + _FINALIZATION_TIMEOUT + while True: + remaining_time(deadline, "stored conversation finalization") + try: + conversation = conversations.get(agent_name, conversation_id) + except ResourceNotFoundError: + pass + else: + if conversation.id != conversation_id: + raise RuntimeError("The service returned a different stored conversation ID.") + if conversation.status == "failed": + raise RuntimeError(f"Sample conversation persistence failed: {conversation.last_error}") + if conversation.status == "completed": + try: + conversations.get_audio(agent_name, conversation_id) + except HttpResponseError as exc: + if exc.status_code != 409 or getattr(exc.error, "code", None) != "recording_not_ready": + raise + else: + items = conversations.list_items(agent_name, conversation_id, limit=20, order="asc") + if any( + isinstance(item, models.VoiceAgentLiveOutputConversationItem) and item.audio is not None + for item in islice(items, 20) + ): + return + elif conversation.status != "in_progress": + raise RuntimeError(f"Unexpected sample conversation status: {conversation.status}") + time.sleep(min(1.0, remaining_time(deadline, "stored conversation finalization"))) + + +@contextmanager +def _temporary_conversation(project_client: AIProjectClient, model: str) -> Iterator[tuple[str, str]]: + agent_name = sample_agent_name("rest") + conversations = project_client.beta.voice_agents.live_conversations + with ExitStack() as cleanup: + agent = project_client.agents.create_version( + agent_name=agent_name, + definition=models.VoiceAgentLiveDefinition( + model=model, + model_type=models.VoiceModelType.SELF_DEPLOYED, + instructions="Greet the caller briefly.", + greeting=models.VoiceAgentTemplateGreetingConfig(text="Hello, welcome."), + audio=audio_settings(), + delegation=models.VoiceAgentLiveClientDelegation(), + store=True, + ), + ) + cleanup.callback(project_client.agents.delete_version, agent_name=agent_name, agent_version=agent.version) + with project_client.beta.voice_agents.live.connect( + agent_name=agent_name, agent_version=agent.version, store=True + ) as connection: + try: + started = wait_for_event(connection, "session.started") + stored_id = started.get("conversation_id") + if not isinstance(stored_id, str) or not stored_id.strip() or stored_id == started["session"]["id"]: + raise RuntimeError("The stored session did not return a valid stored conversation ID.") + conversation_id = stored_id + cleanup.callback(conversations.delete, agent_name, conversation_id) + print(f"Created conversation: {conversation_id}") + _receive_greeting(connection) + finally: + close_session(connection) + _wait_for_recording(conversations, agent_name, conversation_id) + yield agent_name, conversation_id + print(f"Deleted sample conversation: {conversation_id} and temporary agent version: {agent.version}") + + +def _read_item( + conversations: BetaVoiceAgentsLiveConversationsOperations, + agent_name: str, + conversation_id: str, + item_id: str, + index: int, + output_directory: Path, +) -> None: + detail = conversations.get_item(agent_name, conversation_id, item_id) + print(f"Item {detail.id}: type={detail.type}") + if not isinstance( + detail, (models.VoiceAgentLiveInputConversationItem, models.VoiceAgentLiveOutputConversationItem) + ): + print(" Non-speech item; there is no speech audio to download.") + return + safe_print(f" Transcript: {detail.transcription or '(not captured)'}") + if detail.audio is None: + print(" No captured audio metadata for this speech item.") + return + audio = conversations.get_audio_item(agent_name, conversation_id, item_id) + print(f" Audio: role={audio.role}, sample_rate={audio.sample_rate}, duration={audio.duration_ms}") + if audio.blob_uri: + print(" BYOS item: download from your storage using your own credentials.") + raise RuntimeError("This sample downloads Foundry-managed audio only, not BYOS audio.") + with recording_output(output_directory / f"item-{index:04d}.wav") as output: + for chunk in conversations.download_audio_item(agent_name, conversation_id, item_id): + output.write(chunk) + + +def _read_conversation( + conversations: BetaVoiceAgentsLiveConversationsOperations, + agent_name: str, + conversation_id: str, +) -> None: + conversation = conversations.get(agent_name, conversation_id) + if conversation.status != "completed": + raise RuntimeError( + f"The stored session must finish successfully before reading its recording; " + f"status={conversation.status}, error={conversation.last_error}" + ) + print(f"Conversation {conversation.id}: status={conversation.status}, created_at={conversation.created_at}") + + print("Recent stored Live conversations (up to five):") + for recent in islice(conversations.list(agent_name, limit=5, order="desc"), 5): + print(f" {recent.id}: status={recent.status}") + + output_directory = Path(mkdtemp(prefix="voice-agent-live-")) + print(f"Audio output directory: {output_directory}") + + seen_items: set[str] = set() + for index, item in enumerate(conversations.list_items(agent_name, conversation_id, limit=20, order="asc"), 1): + if item.id in seen_items: + raise RuntimeError("The conversation pager repeated an item instead of advancing.") + seen_items.add(item.id) + _read_item(conversations, agent_name, conversation_id, item.id, index, output_directory) + + recording = conversations.get_audio(agent_name, conversation_id) + print( + f"Merged recording: format={recording.format}, sample_rate={recording.sample_rate}, " + f"channels={recording.channels}, duration={recording.duration_ms}" + ) + if recording.blob_uri: + print("BYOS recording: download from your storage using your own credentials.") + raise RuntimeError("This sample downloads Foundry-managed audio only, not BYOS audio.") + with recording_output(output_directory / "conversation.wav") as output: + for chunk in conversations.download_audio(agent_name, conversation_id): + output.write(chunk) + + +def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ.get("FOUNDRY_VOICE_AGENT_NAME", "").strip() + conversation_id = os.environ.get("FOUNDRY_VOICE_CONVERSATION_ID", "").strip() + model = "" + if conversation_id: + if not agent_name: + raise ValueError("Provide a nonblank existing agent name with the stored Foundry conversation ID.") + else: + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"].strip() + if not model: + raise ValueError("Provide a nonblank GPT Live deployment name to create the sample conversation.") + + with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + try: + if conversation_id: + _read_conversation(project_client.beta.voice_agents.live_conversations, agent_name, conversation_id) + print( + "Read-only REST run: the existing agent, conversation, items, and stored audio were not modified." + ) + else: + with _temporary_conversation(project_client, model) as (created_agent, created_conversation): + _read_conversation( + project_client.beta.voice_agents.live_conversations, created_agent, created_conversation + ) + except HttpResponseError as exc: + print(f"GPT Live conversation REST request failed: HTTP {exc.status_code}.") + if exc.status_code == 404: + print( + "Confirm the stored conversation ID and store=True, and that this deployment supports " + "/protocols/voice/live/conversations. No older-route fallback is used." + ) + elif exc.status_code == 409: + print("Recording finalization may still be pending or unavailable; inspect the service error code.") + raise + + +if __name__ == "__main__": + main() diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py new file mode 100644 index 000000000000..54edf6d86b46 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py @@ -0,0 +1,112 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Send text through GPT Live and print the Responses backend's reply. + Set TEXT_PROMPTS to a list for multiple turns in one session. + The sample deletes its temporary agent version when finished. + +USAGE: + python sample_voice_agent_live_text_conversation_async.py + + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required) - Your GPT Live deployment name. + 3) FOUNDRY_MODEL_NAME (required) - A Responses deployment available to Live. + 4) FOUNDRY_VOICE_AGENT_NAME (optional) - Prefix for the temporary agent name. + + Uses DefaultAzureCredential. No audio devices are needed. + Printed text does not mean voice playback has finished. +""" + +from __future__ import annotations + +import asyncio +import os +from typing import Optional, Sequence + +from dotenv import load_dotenv +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects import models + +from live_sample_utils import ( + audio_settings, + close_session_async, + receive_response_async, + safe_print, + sample_agent_name, + text_conversation_prompts, + wait_for_event_async, +) + +TEXT_PROMPTS: Optional[Sequence[str]] = None + + +async def _run_text_conversation( + project_client: AIProjectClient, agent_name: str, agent_version: str, prompts: Sequence[str] +) -> None: + async with project_client.beta.voice_agents.live.connect( + agent_name=agent_name, agent_version=agent_version, store=False + ) as connection: + try: + await wait_for_event_async(connection, "session.started") + for prompt in prompts: + safe_print(f"You: {prompt}") + await connection.response.item.create( + item={"type": "message", "role": "user", "content": [{"type": "input_text", "text": prompt}]} + ) + await connection.response.create() + text, calls = await receive_response_async(connection) + if calls: + raise RuntimeError("The text-only backend unexpectedly requested a function tool.") + if not text: + raise RuntimeError("The Responses backend completed without returning any output text.") + safe_print(f"Responses backend: {text}") + finally: + await close_session_async(connection) + + +async def main() -> None: + prompts = text_conversation_prompts(TEXT_PROMPTS) + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"] + backend_model = os.environ["FOUNDRY_MODEL_NAME"] + agent_name = sample_agent_name("text") + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, + ): + created_version = None + try: + created_version = await project_client.agents.create_version( + agent_name=agent_name, + definition=models.VoiceAgentLiveDefinition( + model=model, + model_type=models.VoiceModelType.SELF_DEPLOYED, + instructions="You are a friendly voice assistant. Delegate text questions to the backend.", + audio=audio_settings(), + delegation=models.VoiceAgentLiveResponsesDelegation( + responses=models.LiveResponsesDelegationSettingsInputParam( + model=backend_model, instructions="Answer in one short sentence." + ) + ), + store=False, + ), + ) + await _run_text_conversation(project_client, agent_name, created_version.version, prompts) + finally: + if created_version is not None: + await project_client.agents.delete_version(agent_name=agent_name, agent_version=created_version.version) + print(f"Deleted sample agent version: {created_version.version}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation.py index acbd0aca3c96..478c72963766 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation.py @@ -6,44 +6,27 @@ """ DESCRIPTION: - This sample demonstrates reading a persisted voice conversation back over - the read-only conversation API exposed by `project_client.beta.voice_agents.conversations`: - the conversation envelope, its responses (model inference turns), and its - ordered items (the transcript). Conversations are created and written by - the voice orchestrator during a live session; this client can only read - them, and only when the agent was configured with `store=True` (see - sample_voice_agent_basic.py). - - Runs with no setup beyond the endpoint: if FOUNDRY_VOICE_CONVERSATION_ID is - not set, this sample creates a temporary voice agent, holds one short - realtime text turn to produce a real conversation, reads it back, then - deletes the agent version it created. Set FOUNDRY_VOICE_AGENT_NAME to hold - that conversation against your own existing agent instead -- it is never - created, modified, or deleted by this sample. Additionally set - FOUNDRY_VOICE_CONVERSATION_ID to skip holding a new conversation entirely - and just read back one your agent already produced. + Read a stored Realtime conversation, its model replies, and its transcript + through project_client.beta.voice_agents.conversations. + + With no conversation ID, send one text message to create a conversation. + With no agent name, also create a temporary agent and delete its version + afterward. An existing agent is not changed or deleted. Conversations + created on an existing agent remain stored. USAGE: python sample_voice_agent_read_conversation.py - Before running the sample: - pip install "azure-ai-projects[voice]>=2.7.0" python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. - 2) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of an existing voice agent - (configured with `store=True`) to hold or read a conversation on. - Defaults to a temporary agent, created and deleted by this sample, when - unset. - 3) FOUNDRY_VOICE_CONVERSATION_ID - Optional. The id of a persisted - conversation owned by FOUNDRY_VOICE_AGENT_NAME. If unset, this sample - holds one short realtime text turn to produce one; see - voice_sample_util.py in this folder and - sample_voice_agent_realtime_text_conversation.py for a full interactive - version. - 4) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier, used only when creating the temporary agent. Defaults to "gpt-realtime". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_NAME (optional) - Existing agent with store=True; + omit to create a temporary agent. + 3) FOUNDRY_VOICE_CONVERSATION_ID (optional) - Completed conversation from + that agent. Omit to create a conversation with a text message. + 4) FOUNDRY_VOICE_AGENT_MODEL (optional) - Model for a temporary agent; + defaults to "gpt-realtime". """ import os diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation_audio.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation_audio.py index 4cdbf5bcd897..40171cba2fec 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation_audio.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation_audio.py @@ -6,50 +6,32 @@ """ DESCRIPTION: - This sample demonstrates reading the persisted audio of a voice - conversation via `project_client.beta.voice_agents.conversations`, both the - merged whole-call recording and a single turn's audio segment. For each it - reads the metadata first, then streams the WAV bytes to a local file. The - merged recording is stereo: the caller on the left channel and the agent - on the right. - - Audio is available only after the session has ended and only when the - agent was configured with `store=True`. For bring-your-own-storage (BYOS) - accounts the metadata carries a `blob_uri` instead, and the bytes are read - from your own storage rather than streamed here. - - Runs with no setup beyond the endpoint: if FOUNDRY_VOICE_CONVERSATION_ID is - not set, this sample creates a temporary voice agent, holds one short - realtime text turn to produce a real conversation, then reads its audio - back -- the agent's reply is real synthesized speech either way, so both - the merged recording and the reply's own audio segment are available even - though the turn itself was typed. Set FOUNDRY_VOICE_AGENT_NAME to hold that - conversation against your own existing agent instead -- it is never - created, modified, or deleted by this sample. Additionally set - FOUNDRY_VOICE_CONVERSATION_ID to skip holding a new conversation entirely - and just read back the audio of one your agent already produced. + Download a stored Realtime conversation's WAV recording and one reply's + audio. The whole-call recording has caller audio on the left channel and + agent audio on the right. The session must have ended with store=True. + + With no conversation ID, send a text message to produce a spoken reply. + With no agent name, also create a temporary agent and delete its version + afterward. An existing agent is not changed or deleted. Conversations + created on an existing agent remain stored. + + Files are saved in the current directory and contain conversation content. + For bring-your-own-storage (BYOS) recordings, the sample prints the blob + location; use your own storage credentials to download the audio. USAGE: python sample_voice_agent_read_conversation_audio.py - Before running the sample: - pip install "azure-ai-projects[voice]>=2.7.0" python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. - 2) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of an existing voice - agent (configured with `store=True`) to hold or read a conversation on. - Defaults to a temporary agent, created and deleted by this sample, when - unset. - 3) FOUNDRY_VOICE_CONVERSATION_ID - Optional. The id of a persisted - conversation owned by FOUNDRY_VOICE_AGENT_NAME. If unset, this sample - holds one short realtime text turn to produce one; see - voice_sample_util.py in this folder and - sample_voice_agent_realtime_text_conversation.py for a full interactive - version. - 4) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier, used only when creating the temporary agent. Defaults to "gpt-realtime". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_NAME (optional) - Existing agent with store=True; + omit to create a temporary agent. + 3) FOUNDRY_VOICE_CONVERSATION_ID (optional) - Completed conversation from + that agent. Omit to create a conversation with a text message. + 4) FOUNDRY_VOICE_AGENT_MODEL (optional) - Model for a temporary agent; + defaults to "gpt-realtime". """ import os diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_generated_audio.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_generated_audio.py new file mode 100644 index 000000000000..0366b4e97ade --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_generated_audio.py @@ -0,0 +1,72 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +""" +DESCRIPTION: + Download generated, unheard audio from an existing interrupted Realtime + reply. This read-only REST sample never creates or deletes resources. + +USAGE: + python sample_voice_agent_read_generated_audio.py + pip install azure-ai-projects azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_NAME (required) - Agent owning the conversation. + 3) FOUNDRY_VOICE_CONVERSATION_ID (required) - Completed, stored conversation. + 4) FOUNDRY_VOICE_ITEM_ID (required) - Stored assistant item ID from REST. + 5) FOUNDRY_VOICE_RECORDING_OUTPUT_PATH (optional) - New WAV output filename. + The file contains generated conversation content. + + Uses DefaultAzureCredential. The artifact must already exist; otherwise + the service returns an error. Use the item ID from REST list_items, + not a WebSocket item ID. Existing output files are never overwritten. +""" + +import io +import os +from pathlib import Path +import wave + +from dotenv import load_dotenv +from azure.ai.projects import AIProjectClient +from azure.identity import DefaultAzureCredential + +from live_sample_utils import recording_output + + +def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + agent_name = os.environ["FOUNDRY_VOICE_AGENT_NAME"] + conversation_id = os.environ["FOUNDRY_VOICE_CONVERSATION_ID"] + item_id = os.environ["FOUNDRY_VOICE_ITEM_ID"] + output = os.environ.get("FOUNDRY_VOICE_RECORDING_OUTPUT_PATH") + if output and Path(output).exists(): + raise FileExistsError(f"The recording output already exists: {output}") + + with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as client, + ): + conversations = client.beta.voice_agents.conversations + metadata = conversations.get_generated_audio_item(agent_name, conversation_id, item_id) + print(f"Generated audio metadata: format={metadata.format}, duration={metadata.duration_ms}.") + if metadata.blob_uri: + print("Generated audio is in customer storage; download it using your own storage credentials.") + return + content = b"".join(conversations.download_generated_audio_item(agent_name, conversation_id, item_id)) + if content[:4] != b"RIFF" or content[8:12] != b"WAVE": + raise ValueError("The generated audio download is not a WAV file.") + with wave.open(io.BytesIO(content), "rb") as recording: + if recording.getnframes() == 0: + raise ValueError("The generated audio download contains no audio frames.") + print(f"Downloaded {len(content)} generated WAV bytes.") + if output: + with recording_output(Path(output)) as destination: + destination.write(content) + + +if __name__ == "__main__": + main() diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_audio_conversation_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_audio_conversation_async.py index e974e8dbb70f..bdbd43523faf 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_audio_conversation_async.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_audio_conversation_async.py @@ -6,38 +6,24 @@ """ DESCRIPTION: - End-to-end hands-free, bidirectional voice conversation using the - ``client.beta.voice_agents.realtime`` namespace added on top of the generated - azure-ai-projects client (see ``azure.ai.projects.aio.operations.AsyncBetaRealtime``). - This mirrors the ergonomics of the OpenAI Python realtime client. - - 1. Create a voice agent with conversation persistence enabled - (`store=True`) so the conversation can be read back afterward. - 2. Stream live mic audio and let the agent's server-side VAD detect your - turns: your speech is transcribed, the agent replies through the - speakers, and talking over it barges in. - 3. Fetch the persisted conversation back by id. - 4. Delete the agent created for this sample. - - Capture and playback use non-blocking pyaudio callbacks; reply audio is - sequence-numbered so a barge-in can skip whatever is still queued. The - agent owns turn detection and noise suppression server-side. Use a headset - to avoid echo. - - Mic audio is sent as base64 PCM16; the reply arrives as typed - ``response.output_audio.*`` events, decoded to PCM16, mono, 24 kHz. - Requires ``aiohttp`` and ``pyaudio``. - - pip install "azure-ai-projects[voice]>=2.7.0" azure-identity pyaudio + Talk to a Realtime voice agent through your microphone and speakers. + The service detects speech turns and lets you interrupt a reply by speaking. + The sample prints transcripts. Use headphones to avoid echo. + + The sample sends and receives PCM16, mono, 24-kHz audio at the same time. + It creates an agent with store=True, reads back the conversation when you + stop, and deletes its agent version. USAGE: python sample_voice_agent_realtime_audio_conversation_async.py + pip install "azure-ai-projects[voice]>=2.7.0" azure-identity python-dotenv pyaudio + Environment variables: 1) FOUNDRY_PROJECT_ENDPOINT (required) - Foundry project endpoint: https://.services.ai.azure.com/api/projects/ - 2) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". + 2) FOUNDRY_VOICE_AGENT_MODEL (optional) - Managed Realtime model; + defaults to "gpt-realtime". 3) FOUNDRY_VOICE_AGENT_NAME - Optional. Name for the agent created by this sample. Defaults to "sample-realtime-audio-conversation-agent-async". @@ -56,9 +42,7 @@ from azure.core.exceptions import HttpResponseError from azure.identity.aio import DefaultAzureCredential -# AsyncBetaRealtimeConnection is re-exported dynamically via aio/operations/_patch.py's `__all__`; -# pylint's static import resolution cannot trace that, but the symbol is valid (verified by -# Pyright/mypy). +# This public re-export is not recognized by Pylint's import resolver. from azure.ai.projects.aio.operations import AsyncBetaRealtimeConnection # pylint: disable=no-name-in-module from azure.ai.projects.aio import AIProjectClient from azure.ai.projects.models import ( @@ -69,6 +53,7 @@ RealtimeServerEventResponseAudioTranscriptDone, RealtimeServerEventResponseCreated, RealtimeServerEventResponseDone, + RealtimeServerEventResponseTextDone, RealtimeServerEventSessionCreated, RealtimeServerEventError, VoiceAgentAudioConfig, @@ -357,6 +342,15 @@ async def _run_audio_conversation(client: AIProjectClient, agent_name: str) -> O try: async for event in conn: + # The public models use GA response.output_* names; legacy aliases remain raw mappings. + if isinstance(event, dict): + event_type = event.get("type") + if event_type in ("response.output_audio.delta", "response.audio.delta"): + event = RealtimeServerEventResponseAudioDelta(event) + elif event_type in ("response.output_audio_transcript.done", "response.audio_transcript.done"): + event = RealtimeServerEventResponseAudioTranscriptDone(event) + elif event_type in ("response.output_text.done", "response.text.done"): + event = RealtimeServerEventResponseTextDone(event) if isinstance(event, RealtimeServerEventSessionCreated): # The persisted conversation id (only present when conversation # persistence is enabled) is set here, not on response.done. @@ -385,6 +379,8 @@ async def _run_audio_conversation(client: AIProjectClient, agent_name: str) -> O ap.queue_audio(event.delta) elif isinstance(event, RealtimeServerEventResponseAudioTranscriptDone): _safe_print(f"Agent: {event.transcript}") + elif isinstance(event, RealtimeServerEventResponseTextDone): + _safe_print(f"Agent: {event.text}") elif isinstance(event, RealtimeServerEventResponseDone): response_active = False except (KeyboardInterrupt, asyncio.CancelledError): diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_function_tool.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_function_tool_async.py similarity index 73% rename from sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_function_tool.py rename to sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_function_tool_async.py index ec3f85c02435..931c53a3a45c 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_function_tool.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_function_tool_async.py @@ -6,39 +6,34 @@ """ DESCRIPTION: - This sample demonstrates handling a client-executed `function` tool during - a live voice-agent session: - - 1) Create a voice agent configured with a `get_weather` function tool. - 2) Open a realtime session and send a text turn that should trigger the tool. - 3) Listen for `response.function_call_arguments.done`, execute the function - locally, and send the result back with `conversation.item.create` + - `response.create` so the agent can finish its reply using the tool output. + Create a Realtime voice agent with a local get_weather tool. Send a text + request, run the requested function, return its result, and print the final + reply. Weather values are sample data, not a live forecast. + The sample deletes the agent version it creates. USAGE: - python sample_voice_agent_realtime_function_tool.py - - Before running the sample: + python sample_voice_agent_realtime_function_tool_async.py pip install "azure-ai-projects[voice]>=2.7.0" azure-identity python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. - 2) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (optional) - Managed Realtime model; + defaults to "gpt-realtime". 3) FOUNDRY_VOICE_AGENT_NAME - Optional. Name for the sample voice agent created and deleted by this script. Defaults to "sample-voice-agent-function-tool". """ +import asyncio import json import os import sys from typing import Any, Final, List, Tuple, cast from dotenv import load_dotenv -from azure.identity import DefaultAzureCredential -from azure.ai.projects import AIProjectClient +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient from azure.ai.projects.models import ( RealtimeConversationItemFunctionCallOutput, RealtimeConversationItemMessageUser, @@ -61,7 +56,7 @@ def get_weather(city: str) -> str: - """A trivial local "tool" implementation the agent can call. + """Return sample weather without calling a weather service. :param city: The city to look up. :type city: str @@ -72,14 +67,7 @@ def get_weather(city: str) -> str: def _safe_print(text: str) -> None: - """Print text that may contain characters the current console can't display. - - The agent's reply below is model-generated and can contain characters (curly - quotes, em-dashes, etc.) outside some legacy, non-Unicode console encodings - (for example when stdout is piped/redirected on Windows). Rather than crashing - with UnicodeEncodeError, fall back to replacing just the unsupported characters; - a real interactive UTF-8 console prints unaffected. - """ + """Print model text, replacing characters the console cannot display.""" try: print(text) except UnicodeEncodeError: @@ -87,24 +75,24 @@ def _safe_print(text: str) -> None: print(text.encode(encoding, errors="replace").decode(encoding)) -def _run_turn_with_tool_support(client: AIProjectClient, agent_name: str, prompt: str) -> None: +async def _run_turn_with_tool_support(client: AIProjectClient, agent_name: str, prompt: str) -> None: """Send one turn and resolve any function-call the agent makes before printing its reply. :param client: The Foundry project client. :param agent_name: The voice agent name. :param prompt: The user's message for this turn. - :type client: ~azure.ai.projects.AIProjectClient + :type client: ~azure.ai.projects.aio.AIProjectClient :type agent_name: str :type prompt: str """ - with client.beta.voice_agents.realtime.connect(agent_name=agent_name) as conn: - conn.conversation.item.create( + async with client.beta.voice_agents.realtime.connect(agent_name=agent_name) as conn: + await conn.conversation.item.create( item=RealtimeConversationItemMessageUser( type=RealtimeConversationItemType.MESSAGE, content=[RealtimeConversationItemMessageUserContent(type="input_text", text=prompt)], ) ) - conn.response.create() + await conn.response.create() # Tool outputs collected from the current turn's function-call(s). These are held back # and only sent once this turn's own response.done arrives (below) -- calling @@ -113,11 +101,13 @@ def _run_turn_with_tool_support(client: AIProjectClient, agent_name: str, prompt pending_tool_outputs: List[Tuple[str, str]] = [] while True: try: - event = conn.recv(timeout=_RESPONSE_TIMEOUT) + event = await asyncio.wait_for(conn.recv(), timeout=_RESPONSE_TIMEOUT) except TimeoutError: print("Timed out waiting for the agent's reply.") - conn.response.cancel() + await conn.response.cancel() return + if isinstance(event, dict) and event.get("type") in ("response.output_text.done", "response.text.done"): + event = RealtimeServerEventResponseTextDone(event) if isinstance(event, RealtimeServerEventResponseFunctionCallArgumentsDone): # The service forwards the call to us; execute it locally now, but defer sending # the result until this response's own response.done arrives. @@ -141,11 +131,11 @@ def _run_turn_with_tool_support(client: AIProjectClient, agent_name: str, prompt # The function-call response has now fully completed, so it's safe to submit # its tool output(s) and ask for a new response. for call_id, result in pending_tool_outputs: - conn.conversation.item.create( + await conn.conversation.item.create( item=RealtimeConversationItemFunctionCallOutput(call_id=call_id, output=result) ) pending_tool_outputs = [] - conn.response.create() + await conn.response.create() elif not any( (item.get("type") if isinstance(item, dict) else getattr(item, "type", None)) == "function_call" for item in (event.response.output or []) @@ -156,7 +146,7 @@ def _run_turn_with_tool_support(client: AIProjectClient, agent_name: str, prompt return -def main() -> None: +async def main() -> None: endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] model = os.environ.get("FOUNDRY_VOICE_AGENT_MODEL") or "gpt-realtime" agent_name = os.environ.get("FOUNDRY_VOICE_AGENT_NAME") or "sample-voice-agent-function-tool" @@ -174,13 +164,13 @@ def main() -> None: ), ) - with ( + async with ( DefaultAzureCredential() as credential, AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, ): created_version = None try: - created_version = project_client.agents.create_version( + created_version = await project_client.agents.create_version( agent_name=agent_name, definition=VoiceAgentDefinition( model_type=VoiceModelType.MANAGED, @@ -195,12 +185,14 @@ def main() -> None: ) print(f"Created voice agent: {agent_name}") - _run_turn_with_tool_support(project_client, agent_name, "What's the weather like in Seattle right now?") + await _run_turn_with_tool_support( + project_client, agent_name, "What's the weather like in Seattle right now?" + ) finally: if created_version is not None: - project_client.agents.delete_version(agent_name=agent_name, agent_version=created_version.version) + await project_client.agents.delete_version(agent_name=agent_name, agent_version=created_version.version) print(f"Deleted voice agent version: {created_version.version}") if __name__ == "__main__": - main() + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_interruption_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_interruption_async.py new file mode 100644 index 000000000000..5b0e06aedee7 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_interruption_async.py @@ -0,0 +1,75 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +""" +DESCRIPTION: + Cancel a Realtime reply and confirm that its audio item was truncated. + No audio is played, so the sample reports zero heard milliseconds. + It deletes its own conversation and agent version afterward. + +USAGE: + python sample_voice_agent_realtime_interruption_async.py + pip install "azure-ai-projects[voice]" azure-identity python-dotenv + + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (required) - A managed Realtime model deployment. + 3) FOUNDRY_VOICE_AGENT_NAME (optional) - Prefix for the temporary agent. + + Uses DefaultAzureCredential; no audio devices are needed. A real player + must report its actual playback position, not zero. +""" + +import asyncio +import os +from uuid import uuid4 + +from dotenv import load_dotenv +from azure.identity.aio import DefaultAzureCredential +from azure.ai.projects.aio import AIProjectClient +from azure.core.exceptions import ResourceNotFoundError + +from realtime_interruption_utils import ( + InterruptedTurn, + interrupt_reply_async, + interruption_definition, +) + + +async def main() -> None: + load_dotenv() + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model = os.environ["FOUNDRY_VOICE_AGENT_MODEL"] + prefix = os.environ.get("FOUNDRY_VOICE_AGENT_NAME") or "sample-realtime-interruption" + agent_name = f"{prefix}-{uuid4().hex[:8]}" + turn = InterruptedTurn() + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as client, + ): + created = None + try: + created = await client.agents.create_version( + agent_name=agent_name, definition=interruption_definition(model) + ) + async with client.beta.voice_agents.realtime.connect(agent_name=agent_name) as connection: + await interrupt_reply_async(connection, turn) + print( + f"Confirmed response cancellation and item truncation. Received {turn.received_audio_bytes} PCM bytes." + ) + finally: + try: + if turn.conversation_id: + try: + await client.beta.voice_agents.conversations.delete(agent_name, turn.conversation_id) + except ResourceNotFoundError: + print("Conversation cleanup returned 404; no persisted conversation was found.") + finally: + if created is not None: + await client.agents.delete_version(agent_name=agent_name, agent_version=created.version) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation.py deleted file mode 100644 index 409c530cb79a..000000000000 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation.py +++ /dev/null @@ -1,416 +0,0 @@ -# pylint: disable=line-too-long,useless-suppression -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ - -""" -DESCRIPTION: - End-to-end typed conversation using the ``client.beta.voice_agents.realtime`` namespace added - on top of the generated azure-ai-projects client (see - ``azure.ai.projects.operations.BetaRealtime``). - - 1. Create a voice agent with conversation persistence enabled - (`store=True`) so the conversation can be read back afterward. - 2. Hold a typed, multi-turn conversation: each prompt is sent as a - ``RealtimeConversationItemMessageUser`` and the reply streams back as - typed audio and transcript events. Blank line (or ``exit`` / ``quit``) - ends it. - 3. Fetch the persisted conversation back by id. - 4. Delete the agent created for this sample. - - Reply audio is PCM16, mono, 24 kHz and plays through the speakers when - ``pyaudio`` is installed; runs headless otherwise. For a hands-free mic - conversation with barge-in, see sample_voice_agent_realtime_audio_conversation_async.py - (that sample needs concurrent send/receive so it stays async-only; see - sample_voice_agent_realtime_text_conversation_async.py for the async version of - this one). - - pip install "azure-ai-projects[voice]>=2.7.0" azure-identity pyaudio - -USAGE: - python sample_voice_agent_realtime_text_conversation.py - - Environment variables: - 1) FOUNDRY_PROJECT_ENDPOINT (required) - Foundry project endpoint: - https://.services.ai.azure.com/api/projects/ - 2) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". - 3) FOUNDRY_VOICE_AGENT_NAME - Optional. Name for the agent created by this - sample. Defaults to "sample-realtime-text-conversation-agent". - - Authenticates with DefaultAzureCredential, so sign in first (e.g. `az login`). -""" - -import os -import sys -import time -from typing import Final, Optional, TYPE_CHECKING - -from dotenv import load_dotenv -from azure.core.exceptions import HttpResponseError -from azure.identity import DefaultAzureCredential -from azure.ai.projects import AIProjectClient -from azure.ai.projects.models import ( - RealtimeConversationItemMessageUser, - RealtimeConversationItemMessageUserContent, - RealtimeConversationItemType, - RealtimeServerEventResponseAudioDelta, - RealtimeServerEventResponseAudioTranscriptDone, - RealtimeServerEventResponseCreated, - RealtimeServerEventResponseDone, - RealtimeServerEventSessionCreated, - RealtimeServerEventError, - VoiceAgentAudioConfig, - VoiceAgentAudioOutputConfig, - VoiceAgentDefinition, - VoiceAgentTemplateGreetingConfig, - VoiceModelType, - VoiceOutputModality, - VoiceType, -) - -if TYPE_CHECKING: - from azure.ai.projects.operations import BetaRealtimeConnection - - -load_dotenv() - - -def _safe_print(text: str) -> None: - """Print text that may contain characters the current console can't display. - - The agent's replies below are model-generated and can contain characters (curly - quotes, em-dashes, etc.) outside some legacy, non-Unicode console encodings - (for example when stdout is piped/redirected on Windows). Rather than crashing - with UnicodeEncodeError, fall back to replacing just the unsupported characters; - a real interactive UTF-8 console prints unaffected. - """ - try: - print(text) - except UnicodeEncodeError: - encoding = sys.stdout.encoding or "ascii" - print(text.encode(encoding, errors="replace").decode(encoding)) - - -# Seconds to wait for the agent to finish its reply. -_RESPONSE_TIMEOUT: Final = 45 - -# Reply audio format: PCM16, mono, 24 kHz. -_SAMPLE_RATE: Final = 24000 - - -def _format_size(num_bytes: int) -> str: - """Format a byte count as a human-readable string. - - :param num_bytes: The size in bytes. - :type num_bytes: int - :return: A string like "12345 bytes (12.1 KB)" or "2097152 bytes (2.00 MB)". - :rtype: str - """ - if num_bytes < 1024: - return f"{num_bytes} bytes" - if num_bytes < 1024 * 1024: - return f"{num_bytes} bytes ({num_bytes / 1024:.1f} KB)" - return f"{num_bytes} bytes ({num_bytes / (1024 * 1024):.2f} MB)" - - -try: - import pyaudio # type: ignore[import-not-found] -except ImportError: # pragma: no cover - optional playback dependency - pyaudio = None # type: ignore[assignment] - - -class _SpeakerPlayer: - """Play streamed PCM16 audio through the speakers with pyaudio. - - Optional: without pyaudio the player is a no-op and the sample still runs - headless, reporting how much audio it received. - """ - - def __init__(self) -> None: - self._audio = None - self._stream = None - self._bytes = 0 - if pyaudio is not None: - self._audio = pyaudio.PyAudio() - self._stream = self._audio.open( - format=pyaudio.paInt16, - channels=1, - rate=_SAMPLE_RATE, - output=True, - ) - - @property - def enabled(self) -> bool: - return self._stream is not None - - def play(self, pcm: bytes) -> None: - """Write one decoded PCM16 chunk to the speaker. - - :param pcm: Decoded PCM16 audio bytes. - :type pcm: bytes - """ - self._bytes += len(pcm) - if self._stream is not None: - self._stream.write(pcm) - - def close(self) -> None: - """Drain and release the audio device.""" - if self._stream is not None: - self._stream.stop_stream() - self._stream.close() - self._stream = None - if self._audio is not None: - self._audio.terminate() - self._audio = None - - @property - def bytes_received(self) -> int: - """Total decoded PCM16 output-audio bytes received from the service. - - :rtype: int - """ - return self._bytes - - @property - def seconds(self) -> float: - """Total audio received, in seconds (PCM16 = 2 bytes/sample). - - :rtype: float - """ - return self._bytes / 2 / _SAMPLE_RATE - - -class _CancellationNotConfirmed(Exception): - """Raised when a just-cancelled response's terminal event could not be confirmed within - ``_RESPONSE_TIMEOUT``, leaving the stream in an unknown state.""" - - -def _drain_cancelled_response(conn: "BetaRealtimeConnection", response_id: Optional[str]) -> None: - """Wait (bounded) for a just-cancelled response's terminal event, discarding it and any of - its trailing content events, so the next turn's ``pump()`` doesn't mistake this stale - completion for its own. - - :param conn: The open realtime connection. - :param response_id: The id of the response that was just cancelled, if it was captured from - that response's ``response.created`` event. If None, the first terminal event seen is - accepted, since there is nothing more specific to correlate against. - :type conn: ~azure.ai.projects.BetaRealtimeConnection - :type response_id: str or None - :raises _CancellationNotConfirmed: If no matching terminal event arrives in time. - """ - deadline = time.monotonic() + _RESPONSE_TIMEOUT - while True: - remaining = deadline - time.monotonic() - if remaining <= 0: - raise _CancellationNotConfirmed("Timed out waiting to confirm the cancelled response finished.") - try: - event = conn.recv(timeout=remaining) - except TimeoutError as exc: - raise _CancellationNotConfirmed("Timed out waiting to confirm the cancelled response finished.") from exc - if isinstance(event, RealtimeServerEventResponseDone): - if response_id is None or event.response.id == response_id: - return - # A stray completion for some other response id; keep draining. - elif isinstance(event, RealtimeServerEventError): - print(f"Session error while confirming cancellation: {event.error.message}") - - -def _run_text_conversation( # pylint: disable=too-many-statements - client: AIProjectClient, agent_name: str, has_greeting: bool -) -> Optional[str]: - """Hold a typed, multi-turn conversation. - - :param client: The Foundry project client. - :param agent_name: The existing voice agent name. - :param has_greeting: Whether the agent has a configured greeting, which the service plays - automatically as soon as the session opens (before any user turn). When True, that greeting - is drained and displayed before the interactive loop starts. - :type client: ~azure.ai.projects.AIProjectClient - :type agent_name: str - :type has_greeting: bool - :return: The persisted conversation id, if one is created. - :rtype: str or None - """ - conversation_id: Optional[str] = None - audio_delta_count = 0 - player = _SpeakerPlayer() - played = False - - try: - # Open the realtime session on the voice agent's dedicated route. - with client.beta.voice_agents.realtime.connect(agent_name=agent_name) as conn: - - def pump() -> None: - nonlocal conversation_id, audio_delta_count - active_response_id: Optional[str] = None - while True: - try: - event = conn.recv(timeout=_RESPONSE_TIMEOUT) - except TimeoutError: - print("Timed out waiting for the agent's reply.") - conn.response.cancel(response_id=active_response_id) - # Consume the cancellation's own terminal event now, before the next - # turn starts: otherwise a late response.done for *this* cancelled - # response could be mistaken by the next pump() call for its own, - # ending it early and silently dropping the real next reply. - _drain_cancelled_response(conn, active_response_id) - return - if isinstance(event, RealtimeServerEventSessionCreated): - # The persisted conversation id (only present when conversation - # persistence is enabled) is set here, not on response.done. - conversation_id = event.conversation_id or conversation_id - if isinstance(event, RealtimeServerEventResponseCreated): - active_response_id = event.response.id - if isinstance(event, RealtimeServerEventResponseDone): - return - if isinstance(event, RealtimeServerEventError): - print(f"Session error: {event.error.message}") - return - if isinstance(event, RealtimeServerEventResponseAudioDelta): - # Each delta is a decoded PCM16 chunk; play it. - audio_delta_count += 1 - player.play(event.delta) - elif isinstance(event, RealtimeServerEventResponseAudioTranscriptDone): - _safe_print(f"Agent: {event.transcript}") - - if has_greeting: - # The service sends the configured greeting as its own response cycle the - # instant the session opens, entirely independent of any user turn. Drain and - # display it here, before the interactive loop starts: otherwise the first - # pump() call below (triggered by the user's own first message) could instead - # observe this unrelated, already in-flight response.done and return early, - # silently dropping the real reply to what the user actually typed. - print("(agent is greeting...)") - pump() - - print("Type a message and press Enter. Blank line (or 'exit') ends the session.") - - while True: - prompt = input("You: ").strip() - if not prompt or prompt.lower() in ("exit", "quit"): - break - - # Send the turn and ask the agent to respond. - conn.conversation.item.create( - item=RealtimeConversationItemMessageUser( - type=RealtimeConversationItemType.MESSAGE, - content=[RealtimeConversationItemMessageUserContent(type="input_text", text=prompt)], - ) - ) - conn.response.create() - pump() - except KeyboardInterrupt: - print("\n(ending session...)") - except _CancellationNotConfirmed: - print("Could not confirm a cancelled response finished; ending the session.") - finally: - played = player.enabled - player.close() - - detail = "played" if played else "received" - output_bytes = player.bytes_received - print(f"(streamed {audio_delta_count} audio chunks, {detail} {player.seconds:.2f}s of audio)") - print( - f"Output audio: format=PCM16, sample_rate={_SAMPLE_RATE} Hz, channels=1, " - f"duration={player.seconds:.2f}s, size={_format_size(output_bytes)}" - ) - if not played: - print("(install pyaudio to hear the reply: pip install pyaudio)") - return conversation_id - - -def _read_conversation(client: AIProjectClient, agent_name: str, conversation_id: str) -> None: - """Read the persisted conversation back over the read-only conversation API. - - :param client: The Foundry project client. - :param agent_name: The voice agent name. - :param conversation_id: The persisted conversation id. - :type client: ~azure.ai.projects.AIProjectClient - :type agent_name: str - :type conversation_id: str - """ - conversations = client.beta.voice_agents.conversations - - conversation = conversations.get(agent_name, conversation_id) - print(f"Conversation {conversation.id}: status={conversation.status}, created_at={conversation.created_at}") - - print("Items (transcript):") - for item in conversations.list_items(agent_name, conversation_id): - role = item.get("role") or item.get("type") - # Audio turns expose ``transcript``; text turns expose ``text``. - parts = [(part.get("transcript") or part.get("text") or "").strip() for part in (item.get("content") or [])] - transcript = " ".join(p for p in parts if p) - print(f" - {role} id={item.get('id')}") - if transcript: - _safe_print(f" {transcript}") - - -def text_conversation() -> None: - endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] - model = os.environ.get("FOUNDRY_VOICE_AGENT_MODEL") or "gpt-realtime" - agent_name = os.environ.get("FOUNDRY_VOICE_AGENT_NAME") or "sample-realtime-text-conversation-agent" - - with ( - DefaultAzureCredential() as credential, - AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as project_client, - ): - created_version = None - try: - # 1) Create a voice agent with conversation persistence enabled (`store=True`) so the - # session's conversation can be fetched back by id afterward. - definition = VoiceAgentDefinition( - model_type=VoiceModelType.MANAGED, - model=model, - instructions="You are a friendly voice assistant. Keep replies short and natural.", - audio=VoiceAgentAudioConfig( - output=VoiceAgentAudioOutputConfig(voice="en-US-AvaNeural", voice_type=VoiceType.AZURE_STANDARD), - ), - output_modalities=[VoiceOutputModality.AUDIO], - greeting=VoiceAgentTemplateGreetingConfig(text="Hi, I'm here to help. What can I do for you?"), - store=True, - ) - created_version = project_client.agents.create_version( - agent_name=agent_name, - definition=definition, - ) - - # 2) Hold the realtime conversation against the freshly created agent. - print(f"Starting realtime session with agent: {agent_name}") - conversation_id = _run_text_conversation(project_client, agent_name, has_greeting=True) - - # 3) Fetch the persisted conversation back by id. - if conversation_id: - print(f"Reading persisted conversation {conversation_id}...") - try: - _read_conversation(project_client, agent_name, conversation_id) - except HttpResponseError as e: - print(f"Could not read conversation: {e.status_code} {e.reason}") - # To fetch this session's audio afterward, use - # `project_client.beta.voice_agents.conversations`: - # - get_audio(agent_name, conversation_id) for the merged - # whole-call stereo recording's metadata, then - # download_audio(agent_name, conversation_id) to stream - # the WAV bytes. - # - get_audio_item(agent_name, conversation_id, item_id) for a - # single turn's audio metadata, then - # download_audio_item(agent_name, conversation_id, item_id) - # to stream that turn's bytes. - # See sample_voice_agent_read_conversation_audio.py for a full example. - else: - print("No conversation id was returned; nothing to read.") - except HttpResponseError as e: - print(f"Service responded with an error: {e.status_code} {e.reason}") - finally: - # 4) Clean up the agent created for this sample. - if created_version is not None: - project_client.agents.delete_version(agent_name=agent_name, agent_version=created_version.version) - print(f"Deleted voice agent version: {created_version.version}") - - -if __name__ == "__main__": - try: - text_conversation() - except KeyboardInterrupt: - print("\nInterrupted.") diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation_async.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation_async.py index c638124194c0..3de73c8add8e 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation_async.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_realtime_text_conversation_async.py @@ -6,33 +6,25 @@ """ DESCRIPTION: - End-to-end typed conversation using the ``client.beta.voice_agents.realtime`` namespace added - on top of the generated azure-ai-projects client (see - ``azure.ai.projects.aio.operations.AsyncBetaRealtime``). + Type messages to a Realtime voice agent using the async client and print + its replies. If PyAudio is installed, also play reply audio through your + speakers. Enter a blank line, "exit", or "quit" to finish. - 1. Create a voice agent with conversation persistence enabled - (`store=True`) so the conversation can be read back afterward. - 2. Hold a typed, multi-turn conversation: each prompt is sent as a - ``RealtimeConversationItemMessageUser`` and the reply streams back as - typed audio and transcript events. Blank line (or ``exit`` / ``quit``) - ends it. - 3. Fetch the persisted conversation back by id. - 4. Delete the agent created for this sample. - - Reply audio is PCM16, mono, 24 kHz and plays through the speakers when - ``pyaudio`` is installed; runs headless otherwise. For a hands-free mic - conversation with barge-in, see sample_voice_agent_realtime_audio_conversation_async.py. - - pip install "azure-ai-projects[voice]>=2.7.0" azure-identity pyaudio + The sample creates an agent with store=True, reads back the conversation, + and deletes its agent version. Audio is PCM16, mono, 24 kHz. + For microphone input, use sample_voice_agent_realtime_audio_conversation_async.py. USAGE: python sample_voice_agent_realtime_text_conversation_async.py + pip install "azure-ai-projects[voice]>=2.7.0" azure-identity python-dotenv + pip install pyaudio # Optional speaker playback. + Environment variables: 1) FOUNDRY_PROJECT_ENDPOINT (required) - Foundry project endpoint: https://.services.ai.azure.com/api/projects/ - 2) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". + 2) FOUNDRY_VOICE_AGENT_MODEL (optional) - Managed Realtime model; + defaults to "gpt-realtime". 3) FOUNDRY_VOICE_AGENT_NAME - Optional. Name for the agent created by this sample. Defaults to "sample-realtime-text-conversation-agent-async". @@ -48,9 +40,7 @@ from azure.core.exceptions import HttpResponseError from azure.identity.aio import DefaultAzureCredential -# AsyncBetaRealtimeConnection is re-exported dynamically via aio/operations/_patch.py's `__all__`; -# pylint's static import resolution cannot trace that, but the symbol is valid (verified by -# Pyright/mypy). +# This public re-export is not recognized by Pylint's import resolver. from azure.ai.projects.aio.operations import AsyncBetaRealtimeConnection # pylint: disable=no-name-in-module from azure.ai.projects.aio import AIProjectClient from azure.ai.projects.models import ( @@ -61,6 +51,7 @@ RealtimeServerEventResponseAudioTranscriptDone, RealtimeServerEventResponseCreated, RealtimeServerEventResponseDone, + RealtimeServerEventResponseTextDone, RealtimeServerEventSessionCreated, RealtimeServerEventError, VoiceAgentAudioConfig, @@ -242,6 +233,15 @@ async def _run_text_conversation( # pylint: disable=too-many-statements async def pump() -> None: nonlocal conversation_id, audio_delta_count, active_response_id async for event in conn: + # The public models use GA response.output_* names; legacy aliases remain raw mappings. + if isinstance(event, dict): + event_type = event.get("type") + if event_type in ("response.output_audio.delta", "response.audio.delta"): + event = RealtimeServerEventResponseAudioDelta(event) + elif event_type in ("response.output_audio_transcript.done", "response.audio_transcript.done"): + event = RealtimeServerEventResponseAudioTranscriptDone(event) + elif event_type in ("response.output_text.done", "response.text.done"): + event = RealtimeServerEventResponseTextDone(event) if isinstance(event, RealtimeServerEventSessionCreated): # The persisted conversation id (only present when conversation # persistence is enabled) is set here, not on response.done. @@ -259,6 +259,8 @@ async def pump() -> None: player.play(event.delta) elif isinstance(event, RealtimeServerEventResponseAudioTranscriptDone): _safe_print(f"Agent: {event.transcript}") + elif isinstance(event, RealtimeServerEventResponseTextDone): + _safe_print(f"Agent: {event.text}") if has_greeting: # The service sends the configured greeting as its own response cycle the diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_versions.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_versions.py index ebbff2f47dbc..0e0a83bccfa4 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_versions.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_versions.py @@ -6,24 +6,21 @@ """ DESCRIPTION: - This sample demonstrates working with voice-agent versions. Agents are - immutable: every `create_version` call produces a new version. This sample - creates an agent, adds a new version to it, adds a draft version, lists the - versions, and reads a single version back. + Create published and draft versions of a voice agent, list them, and read + their settings. Each create_version call makes a new version rather than + changing an existing one. USAGE: python sample_voice_agent_versions.py - Before running the sample: - pip install "azure-ai-projects>=2.7.0" python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. - 2) FOUNDRY_VOICE_AGENT_MODEL - Optional. The managed (service-hosted) realtime model - identifier. Defaults to "gpt-realtime". - 3) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of the voice agent. If not - set, defaults to "sample-versioned-voice-agent". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (optional) - Managed Realtime model; + defaults to "gpt-realtime". + 3) FOUNDRY_VOICE_AGENT_NAME (optional) - Agent name; + defaults to "sample-versioned-voice-agent". """ import os diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py index 8b12a235abbb..779605fa8fe0 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py @@ -6,34 +6,26 @@ """ DESCRIPTION: - This sample demonstrates the richer parts of a voice agent definition: + Configure a voice agent with audio settings, speech detection, transcription, + a local function tool, and a service-managed end-conversation tool. + MCP and toolbox settings are shown as examples, not executed. - * Input (microphone) audio configuration: audio format, server-side turn - detection (VAD), input-audio transcription. - * Tools the agent may use during a live session: a client-executed - `function` tool and a service-managed `system` control tool (`mcp` and - `toolbox` tools are shown as constructed objects for illustration). - * Bring-your-own-model (BYOM): set `model_type="self_deployed"` to point - the agent at your own Foundry model deployment instead of a - service-managed model. + Use a managed model, or select "self_deployed" to use your own Foundry + model deployment. USAGE: python sample_voice_agent_with_tools.py - Before running the sample: - pip install "azure-ai-projects>=2.7.0" python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. - 2) FOUNDRY_VOICE_AGENT_MODEL - Optional. The realtime model (managed) or the - Foundry deployment name (BYOM). Defaults to "gpt-realtime". (FOUNDRY_VOICE_MODEL - is a deprecated alias for this variable, still read as a fallback for compatibility - with earlier samples.) - 3) FOUNDRY_VOICE_MODEL_TYPE - Optional. "managed" (default) for a - service-hosted model, or "self_deployed" to bring your own deployment. - 4) FOUNDRY_VOICE_AGENT_NAME - Optional. The name of the voice agent. If not - set, defaults to "sample-voice-agent-with-tools". + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. + 2) FOUNDRY_VOICE_AGENT_MODEL (optional) - Managed model or your deployment + name; defaults to "gpt-realtime". The deprecated FOUNDRY_VOICE_MODEL + variable is still accepted as a fallback. + 3) FOUNDRY_VOICE_MODEL_TYPE (optional) - "managed" (default) or "self_deployed". + 4) FOUNDRY_VOICE_AGENT_NAME (optional) - Agent name; + defaults to "sample-voice-agent-with-tools". """ import os @@ -65,9 +57,7 @@ endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] # Keep existing BYOM configurations targeting the caller's deployment. model = os.environ.get("FOUNDRY_VOICE_AGENT_MODEL") or os.environ.get("FOUNDRY_VOICE_MODEL") or "gpt-realtime" -# "managed" runs a service-hosted model; "self_deployed" (BYOM) uses your own -# Foundry deployment named by `model`. The service derives whether the model is -# realtime or cascaded; you don't set that here. +# Choose a managed model or your own deployment; the service selects its protocol. model_type = os.environ.get("FOUNDRY_VOICE_MODEL_TYPE") or VoiceModelType.MANAGED agent_name = os.environ.get("FOUNDRY_VOICE_AGENT_NAME") or "sample-voice-agent-with-tools" diff --git a/sdk/ai/azure-ai-projects/samples/agents/voice/voice_sample_util.py b/sdk/ai/azure-ai-projects/samples/agents/voice/voice_sample_util.py index a4855a8b6f8a..f3a28cb71b12 100644 --- a/sdk/ai/azure-ai-projects/samples/agents/voice/voice_sample_util.py +++ b/sdk/ai/azure-ai-projects/samples/agents/voice/voice_sample_util.py @@ -30,15 +30,10 @@ def hold_sample_conversation( project_client: AIProjectClient, agent_name: str, prompt: str = "Say a short, friendly hello." ) -> str: - """Send one short realtime text turn to an existing voice agent and return the resulting - persisted conversation id, once it has finished finalizing. + """Send one text message and return its stored Realtime conversation ID. - Samples that read a conversation back (transcript, responses, audio) do not always have a - live call handy to read. This helper produces a minimal real conversation on demand so those - samples can run without requiring a conversation id up front. The agent named ``agent_name`` - must already exist (see sample_voice_agent_basic.py) and be configured with ``store=True`` so - its conversations are persisted. For a full interactive conversation and a fuller explanation - of the realtime event flow used here, see sample_voice_agent_realtime_text_conversation.py. + The agent must already exist with ``store=True``. Wait for storage to finish + before returning so callers can read the replies and transcript. :param project_client: The Foundry project client. :param agent_name: The name of an existing voice agent, configured with ``store=True``. @@ -63,8 +58,7 @@ def hold_sample_conversation( while True: event = conn.recv(timeout=_RESPONSE_TIMEOUT) if isinstance(event, RealtimeServerEventSessionCreated): - # The persisted conversation id (only present when conversation persistence is - # enabled) is set here, not on response.done. + # The stored conversation ID arrives at session creation, not response.done. conversation_id = event.conversation_id or conversation_id if isinstance(event, RealtimeServerEventResponseDone): break @@ -77,10 +71,7 @@ def hold_sample_conversation( "was configured with `store=True`." ) - # `response.done` only means the model finished replying, not that the service has finished - # persisting the conversation -- immediately after the session closes, the conversation can - # still briefly report `in_progress` while that finalization completes in the background. - # Poll until it settles so callers can read a complete transcript right away. + # A reply can finish before its transcript is stored; wait for storage to finish too. conversations = project_client.beta.voice_agents.conversations for _ in range(_FINALIZE_POLL_ATTEMPTS): conversation = conversations.get(agent_name, conversation_id) diff --git a/sdk/ai/azure-ai-projects/samples/logs/sample_log_from_voice_agent.py b/sdk/ai/azure-ai-projects/samples/logs/sample_log_from_voice_agent.py index 698d689f9574..e2b387a59c89 100644 --- a/sdk/ai/azure-ai-projects/samples/logs/sample_log_from_voice_agent.py +++ b/sdk/ai/azure-ai-projects/samples/logs/sample_log_from_voice_agent.py @@ -5,23 +5,21 @@ """ DESCRIPTION: - Capture Voice Agent WebSocket diagnostics from azure.ai.projects.realtime - into a timestamped temporary log file. The SDK logs connection lifecycle, - event types and serialized event sizes, not event payloads or credentials. - No OpenTelemetry configuration or GenAI tracing opt-in is required. + Save Realtime voice-agent diagnostics to a temporary log file using + azure.ai.projects.realtime. Logs contain connection events, event types, + and byte counts, not message content or credentials. OpenTelemetry is + not required. - Create a preview Voice Agent, send one text prompt, wait for its response, - and delete the created version. No microphone or speaker is required. + The sample sends one text prompt and deletes the agent version it creates. + No microphone or speaker is needed. USAGE: python samples/logs/sample_log_from_voice_agent.py - Before running the sample: - pip install "azure-ai-projects[voice]" azure-identity python-dotenv - Set these environment variables with your own values: - 1) FOUNDRY_PROJECT_ENDPOINT - The Azure AI Project endpoint. + Environment variables: + 1) FOUNDRY_PROJECT_ENDPOINT (required) - The Foundry project endpoint. 2) FOUNDRY_VOICE_AGENT_MODEL - Optional managed model; defaults to "gpt-realtime". 3) FOUNDRY_VOICE_AGENT_NAME - Optional agent name; defaults to a unique sample name. diff --git a/sdk/ai/azure-ai-projects/tests/agents/live_agent_crud_test_base.py b/sdk/ai/azure-ai-projects/tests/agents/live_agent_crud_test_base.py new file mode 100644 index 000000000000..f84cade1d93e --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/live_agent_crud_test_base.py @@ -0,0 +1,100 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Narrow preparer and assertions for persisted Live-agent REST tests.""" + +import functools +import re +from uuid import uuid4 + +from azure.ai.projects import models +from devtools_testutils import EnvironmentVariableLoader, add_general_regex_sanitizer + +liveAgentServicePreparer = functools.partial( + EnvironmentVariableLoader, + "", + foundry_project_endpoint="https://sanitized-account-name.services.ai.azure.com/api/projects/sanitized-project-name", + foundry_voice_live_model_name="sanitized-model-deployment-name", + foundry_model_name="sanitized-model-deployment-name", +) + +PROMPT_INSTRUCTIONS = ( + "Handle the delegated question. Return a [thinking] section with a brief task status, " + "not private reasoning, followed by a [commentary] section containing a short answer." +) + + +def owned_agent_name(scenario, *, live): + sanitized = f"sanitized-live-crud-{scenario}" + if not live: + return sanitized + name = f"live-crud-{uuid4().hex}" + add_general_regex_sanitizer(regex=re.escape(name), value=sanitized, function_scoped=True) + return name + + +def sanitize_live_deployments(kwargs): + # Match the package's session-scoped gpt-* fallback regardless of sanitizer order. + for key in ("foundry_voice_live_model_name", "foundry_model_name"): + value = kwargs[key] + assert value + add_general_regex_sanitizer( + regex=re.escape(value), value="sanitized-model-deployment-name", function_scoped=True + ) + + +def live_definition(mode, live_model, backend_model, instructions, *, backend=None): + # Startup rejects acknowledgement_delay_ms; its writable JSON remains covered by model tests. + if mode == "client": + delegation = models.VoiceAgentLiveClientDelegation() + elif mode == "responses": + delegation = models.VoiceAgentLiveResponsesDelegation( + responses=models.LiveResponsesDelegationSettingsInputParam( + model=backend_model, instructions="Answer the question briefly." + ), + ) + elif mode == "foundry_managed_agent": + assert backend is not None + delegation = models.VoiceAgentLiveManagedAgentDelegation(agent_name=backend.name, agent_version=backend.version) + else: + raise ValueError(f"Unknown Live delegation mode: {mode}") + return models.VoiceAgentLiveDefinition( + model_type=models.VoiceModelType.SELF_DEPLOYED, + model=live_model, + instructions=instructions, + store=False, + audio=models.LiveInitialSessionAudioParam( + format=models.LiveSessionAudioFormatPCMParam(rate=24000), + output=models.LiveInitialSessionAudioOutputParam(voice="marin"), + ), + delegation=delegation, + ) + + +def assert_live_version(version, expected, *, name, version_id=None): + assert isinstance(version, models.AgentVersionDetails) + assert version.name == name and version.id and version.version + if version_id is not None: + assert version.version == version_id + definition = version.definition + assert isinstance(definition, models.VoiceAgentLiveDefinition) + assert definition.kind == "voice" + assert definition.sub_protocol == "live" + assert definition.model_type == "self_deployed" + assert definition.model == expected.model + assert definition.instructions == expected.instructions + assert definition.store is False + assert isinstance(definition.audio, models.LiveInitialSessionAudioParam) + assert isinstance(definition.audio.format, models.LiveSessionAudioFormatPCMParam) + assert definition.audio.format.rate == 24000 + assert definition.audio.output.voice == "marin" + assert isinstance(definition.delegation, type(expected.delegation)) + assert definition.delegation.type == expected.delegation.type + if isinstance(definition.delegation, models.VoiceAgentLiveManagedAgentDelegation): + assert definition.delegation.agent_name == expected.delegation.agent_name + assert definition.delegation.agent_version == expected.delegation.agent_version + elif isinstance(definition.delegation, models.VoiceAgentLiveResponsesDelegation): + assert isinstance(definition.delegation.responses, models.LiveResponsesDelegationSettingsInputParam) + assert definition.delegation.responses.model == expected.delegation.responses.model + assert definition.delegation.responses.instructions == expected.delegation.responses.instructions diff --git a/sdk/ai/azure-ai-projects/tests/agents/live_conversation_test_base.py b/sdk/ai/azure-ai-projects/tests/agents/live_conversation_test_base.py new file mode 100644 index 000000000000..d5bf7dc9ef2b --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/live_conversation_test_base.py @@ -0,0 +1,312 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Recording-only Live fixtures and shared REST assertions. + +The preparer runs outside the recorded decorator. Recording creates two owned +stored greeting sessions and waits for durable audio before REST recording +starts. Playback uses sanitized IDs and never opens a WebSocket or creates an +agent. Recording uses an existing GPT Live deployment and needs no microphone +or prerecorded audio file. +""" + +import array +import asyncio +import base64 +from contextlib import AsyncExitStack +from dataclasses import dataclass +import datetime +import functools +import io +import re +import sys +import time +from typing import Any +from urllib.parse import urlsplit +import uuid +import wave + +from azure.ai.projects import models +from azure.ai.projects.aio import AIProjectClient +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from devtools_testutils import EnvironmentVariableLoader, add_general_regex_sanitizer, is_live +from devtools_testutils.preparers import AbstractPreparer + +liveConversationServicePreparer = functools.partial( + EnvironmentVariableLoader, + "", + foundry_project_endpoint="https://sanitized-account-name.services.ai.azure.com/api/projects/sanitized-project-name", + foundry_voice_live_model_name="sanitized-live-deployment-name", +) + +_AGENT = "sanitized-live-rest-agent" +_CONVERSATIONS = ("sanitized-live-conversation-1", "sanitized-live-conversation-2") +_SILENCE = bytes(2400) +_SESSION_TIMEOUT = 45 +_FINALIZATION_TIMEOUT = 90 + + +@dataclass(frozen=True) +class LiveConversationFixture: + agent_name: str + conversation_ids: tuple[str, ...] + item_ids: tuple[tuple[str, ...], ...] = () + version: str = "" + + +def playback_fixture() -> LiveConversationFixture: + return LiveConversationFixture(_AGENT, _CONVERSATIONS) + + +def add_live_conversation_sanitizers(fixture: LiveConversationFixture) -> None: + pairs = [(fixture.agent_name, _AGENT)] + for index, conversation_id in enumerate(fixture.conversation_ids): + pairs.append((conversation_id, _CONVERSATIONS[index])) + for item_index, item_id in enumerate(fixture.item_ids[index]): + pairs.append((item_id, f"sanitized-live-item-{index + 1}-{item_index + 1}")) + for actual, replacement in pairs: + add_general_regex_sanitizer(regex=re.escape(actual), value=replacement, function_scoped=True) + + +def _check_live_error(event: Any) -> None: + if event.get("type") == "error": + error = event.get("error") or {} + raise RuntimeError(f"Live recording fixture failed: {error.get('code')}: {error.get('message')}") + + +async def _receive_event(connection, event_type: str): + deadline = time.monotonic() + _SESSION_TIMEOUT + while time.monotonic() < deadline: + event = await asyncio.wait_for(connection.recv(), timeout=deadline - time.monotonic()) + _check_live_error(event) + if event.get("type") == event_type: + return event + if event.get("type") == "session.closed": + raise RuntimeError(f"Live recording fixture closed early: {event.get('reason')}") + raise TimeoutError(f"Live recording fixture did not receive {event_type}") + + +async def _hold_greeting(client: AIProjectClient, agent_name: str, version: str, conversations: list[str]) -> None: + async with client.beta.voice_agents.live.connect( + agent_name=agent_name, agent_version=version, store=True + ) as connection: + started = await _receive_event(connection, "session.started") + assert started.conversation_id and started.conversation_id != started.session.id + conversations.append(started.conversation_id) + stop = asyncio.Event() + + async def clock(): + while not stop.is_set(): + await connection.session.input_audio.append(audio=_SILENCE) + await asyncio.sleep(0.05) + + sender = asyncio.create_task(clock()) + speech = False + transcript = "" + last_content = time.monotonic() + deadline = time.monotonic() + _SESSION_TIMEOUT + try: + while time.monotonic() < deadline: + if sender.done(): + sender.result() + if speech and transcript.strip() and time.monotonic() - last_content >= 2: + break + try: + event = await asyncio.wait_for(connection.recv(), timeout=min(0.5, deadline - time.monotonic())) + except asyncio.TimeoutError: + continue + _check_live_error(event) + if isinstance(event, models.LiveOutputAudioDelta): + pcm = base64.b64decode(event.delta, validate=True) + assert len(pcm) % 2 == 0 + if any( + abs(int.from_bytes(pcm[i : i + 2], "little", signed=True)) > 256 for i in range(0, len(pcm), 2) + ): + speech = True + last_content = time.monotonic() + elif isinstance(event, models.LiveServerEventLiveOutputTranscriptDelta): + transcript += event.delta + if event.delta.strip(): + last_content = time.monotonic() + elif event.get("type") == "session.closed": + raise RuntimeError("Live recording fixture ended before greeting audio was captured") + else: + raise TimeoutError("Live recording fixture did not finish greeting speech") + finally: + stop.set() + try: + await sender + finally: + await connection.session.close() + closed = await _receive_event(connection, "session.closed") + assert closed.reason == "close_requested" + + +async def _wait_for_recording(client: AIProjectClient, agent_name: str, conversation_id: str) -> tuple[str, ...]: + operations = client.beta.voice_agents.live_conversations + deadline = time.monotonic() + _FINALIZATION_TIMEOUT + while time.monotonic() < deadline: + try: + conversation = await operations.get(agent_name, conversation_id) + except ResourceNotFoundError: + await asyncio.sleep(1) + continue + if conversation.status == "failed": + raise AssertionError(f"Live recording persistence failed: {conversation.last_error}") + if conversation.status == "completed": + try: + recording = await operations.get_audio(agent_name, conversation_id) + except HttpResponseError as exc: + if exc.status_code != 409 or getattr(exc.error, "code", None) != "recording_not_ready": + raise + else: + assert recording.blob_uri is None, "Recorded audio tests require Foundry-managed storage, not BYOS" + items = [item async for item in operations.list_items(agent_name, conversation_id)] + assert items and any( + isinstance(item, models.VoiceAgentLiveOutputConversationItem) and item.audio is not None + for item in items + ) + return tuple(item.id for item in items) + await asyncio.sleep(1) + raise TimeoutError("Live recording fixture did not reach completed persistence/audio state") + + +async def _delete_fixture(client: AIProjectClient, fixture: LiveConversationFixture) -> None: + async def delete_conversation(conversation_id: str) -> None: + try: + await client.beta.voice_agents.live_conversations.delete(fixture.agent_name, conversation_id) + except ResourceNotFoundError: + pass + + async with AsyncExitStack() as cleanup: + cleanup.push_async_callback( + client.agents.delete_version, agent_name=fixture.agent_name, agent_version=fixture.version + ) + for conversation_id in reversed(fixture.conversation_ids): + cleanup.push_async_callback(delete_conversation, conversation_id) + + +class LiveConversationPreparer(AbstractPreparer): + def __init__(self) -> None: + super().__init__("live-rest-", 24, disable_recording=True) + self.resource_moniker = _AGENT + self.fixture: LiveConversationFixture | None = None + self.endpoint: str | None = None + + def create_resource(self, name, **kwargs): + self.fixture = None + self.endpoint = None + if not is_live(): + return {"live_conversation_fixture": playback_fixture()} + self.endpoint = kwargs["foundry_project_endpoint"] + model = kwargs["foundry_voice_live_model_name"] + self.fixture = asyncio.run(self._create_fixture(f"{name}-{uuid.uuid4().hex[:8]}", model)) + return {"live_conversation_fixture": self.fixture} + + async def _create_fixture(self, agent_name: str, model: str) -> LiveConversationFixture: + endpoint = self.endpoint + assert isinstance(endpoint, str) and endpoint.strip(), "A recording fixture needs a project endpoint" + credential = self.test_class_instance.get_credential(AIProjectClient, is_async=True) + async with credential, AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as client: + agent = None + conversation_ids: list[str] = [] + complete = False + try: + agent = await client.agents.create_version( + agent_name=agent_name, + definition=models.VoiceAgentLiveDefinition( + model=model, + model_type=models.VoiceModelType.SELF_DEPLOYED, + instructions="Greet the caller briefly.", + greeting=models.VoiceAgentTemplateGreetingConfig(text="Hello, welcome."), + audio=models.LiveInitialSessionAudioParam( + format=models.LiveSessionAudioFormatPCMParam(rate=24000), + output=models.LiveInitialSessionAudioOutputParam(voice="marin"), + ), + delegation=models.VoiceAgentLiveClientDelegation(), + store=True, + ), + ) + items = [] + for _ in _CONVERSATIONS: + await _hold_greeting(client, agent_name, agent.version, conversation_ids) + items.append(await _wait_for_recording(client, agent_name, conversation_ids[-1])) + fixture = LiveConversationFixture(agent_name, tuple(conversation_ids), tuple(items), agent.version) + complete = True + return fixture + finally: + if agent is not None and not complete: + await _delete_fixture( + client, LiveConversationFixture(agent_name, tuple(conversation_ids), version=agent.version) + ) + + def remove_resource(self, name, **kwargs): + if self.fixture is not None: + asyncio.run(self._cleanup_fixture()) + self.fixture = None + self.endpoint = None + + async def _cleanup_fixture(self) -> None: + fixture, endpoint = self.fixture, self.endpoint + assert fixture is not None and isinstance(endpoint, str), "No owned recording fixture was prepared" + credential = self.test_class_instance.get_credential(AIProjectClient, is_async=True) + async with credential, AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as client: + await _delete_fixture(client, fixture) + + +def assert_live_status(expected: int): + def verify(response): + assert response.http_response.status_code == expected + assert "/protocols/voice/live/conversations" in urlsplit(response.http_request.url).path + assert response.http_request.headers["Foundry-Features"] == "VoiceAgents=V1Preview" + + return verify + + +def assert_completed_conversation(conversation, conversation_id: str) -> None: + assert isinstance(conversation, models.VoiceAgentLiveConversation) + assert conversation.id == conversation_id + assert conversation.object == "voice.conversation" and conversation.status == "completed" + assert isinstance(conversation.created_at, datetime.datetime) + assert isinstance(conversation.completed_at, datetime.datetime) + assert conversation.last_error is None + + +def assert_speech_item(item, expected_id: str | None = None) -> models.VoiceAgentLiveOutputConversationItem: + assert isinstance(item, models.VoiceAgentLiveOutputConversationItem) + assert item.id and (expected_id is None or item.id == expected_id) + assert item.transcription and item.transcription.strip() + assert isinstance(item.audio, models.VoiceAudioItem) + assert item.audio.item_id == item.id + return item + + +def assert_audio_metadata(audio, conversation_id: str, *, item_id: str | None = None) -> None: + assert audio.conversation_id == conversation_id + assert audio.format == "wav" and audio.sample_rate == 24000 + assert isinstance(audio.duration_ms, datetime.timedelta) and audio.duration_ms.total_seconds() > 0 + assert audio.blob_uri is None, "This test must exercise the Foundry-managed content routes" + if item_id is None: + assert isinstance(audio, models.VoiceRecording) and audio.channels == 2 + assert audio.channel_layout.left == "user" and audio.channel_layout.right == "agent" + else: + assert isinstance(audio, models.VoiceAudioItem) and audio.item_id == item_id + assert audio.role == "agent" and audio.channels == 1 and audio.codec == "pcm16" + + +def assert_wav(content: bytes, metadata) -> None: + assert content[:4] == b"RIFF" and content[8:12] == b"WAVE" + with wave.open(io.BytesIO(content), "rb") as recording: + assert recording.getcomptype() == "NONE" and recording.getsampwidth() == 2 + assert recording.getframerate() == metadata.sample_rate + assert recording.getnchannels() == metadata.channels + frames = recording.getnframes() + pcm = recording.readframes(frames) + assert frames > 0 and len(pcm) == frames * metadata.channels * 2 + assert abs(frames / metadata.sample_rate - metadata.duration_ms.total_seconds()) <= 0.01 + samples = array.array("h", pcm) + if sys.byteorder != "little": + samples.byteswap() + channel = 1 if metadata.channels == 2 else 0 + assert any(abs(sample) > 256 for sample in samples[channel :: metadata.channels]), "Expected non-silent agent audio" diff --git a/sdk/ai/azure-ai-projects/tests/agents/realtime_interruption_test_base.py b/sdk/ai/azure-ai-projects/tests/agents/realtime_interruption_test_base.py new file mode 100644 index 000000000000..fd03ff28ae7c --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/realtime_interruption_test_base.py @@ -0,0 +1,196 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Prepare an owned interrupted response outside HTTP recording; playback is offline.""" + +import asyncio +from contextlib import AsyncExitStack +from dataclasses import dataclass +import functools +import logging +from pathlib import Path +import re +import runpy +import time +from urllib.parse import urlsplit +from uuid import uuid4 + +from azure.ai.projects import models +from azure.ai.projects.aio import AIProjectClient +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from devtools_testutils import EnvironmentVariableLoader, add_general_regex_sanitizer, is_live +from devtools_testutils.preparers import AbstractPreparer + +from live_conversation_test_base import assert_wav + +_LOGGER = logging.getLogger(__name__) +_AGENT = "sanitized-interrupted-audio-agent" +_CONVERSATION = "sanitized-interrupted-conversation" +_ITEM = "sanitized-interrupted-item" + +interruptionServicePreparer = functools.partial( + EnvironmentVariableLoader, + "", + foundry_project_endpoint="https://sanitized-account-name.services.ai.azure.com/api/projects/sanitized-project-name", + foundry_voice_model_name="sanitized-realtime-deployment-name", +) + + +@dataclass(frozen=True) +class RealtimeInterruptionFixture: + agent_name: str + conversation_id: str + item_id: str + version: str = "" + + +def playback_fixture() -> RealtimeInterruptionFixture: + return RealtimeInterruptionFixture(_AGENT, _CONVERSATION, _ITEM) + + +def _sample_helpers(): + path = Path(__file__).parents[2] / "samples" / "agents" / "voice" / "realtime_interruption_utils.py" + return runpy.run_path(str(path)) + + +async def _delete_fixture(client: AIProjectClient, fixture: RealtimeInterruptionFixture) -> None: + async def delete_conversation() -> None: + if fixture.conversation_id: + try: + await client.beta.voice_agents.conversations.delete(fixture.agent_name, fixture.conversation_id) + except ResourceNotFoundError: + _LOGGER.info("Owned interrupted conversation was not persisted or was already deleted.") + + async def delete_agent() -> None: + try: + await client.agents.delete(agent_name=fixture.agent_name) + except ResourceNotFoundError: + _LOGGER.info("Owned interruption agent was not created or was already deleted.") + + async with AsyncExitStack() as cleanup: + cleanup.push_async_callback(delete_agent) + cleanup.push_async_callback(delete_conversation) + + +class RealtimeInterruptionPreparer(AbstractPreparer): + def __init__(self) -> None: + super().__init__("interrupted-audio-", 32, disable_recording=True) + self.resource_moniker = _AGENT + self.fixture: RealtimeInterruptionFixture | None = None + self.endpoint: str | None = None + + def create_resource(self, name, **kwargs): + self.fixture = None + self.endpoint = None + if not is_live(): + return {"interrupted_audio_fixture": playback_fixture()} + self.endpoint = kwargs["foundry_project_endpoint"] + model = kwargs["foundry_voice_model_name"] + self.fixture = asyncio.run(self._create_fixture(f"voice-interruption-{uuid4().hex}", model)) + return {"interrupted_audio_fixture": self.fixture} + + async def _create_fixture(self, agent_name: str, model: str) -> RealtimeInterruptionFixture: + helpers = _sample_helpers() + turn = helpers["InterruptedTurn"]() + assert self.endpoint, "A live recording requires a configured project endpoint" + credential = self.test_class_instance.get_credential(AIProjectClient, is_async=True) + async with ( + credential, + AIProjectClient(endpoint=self.endpoint, credential=credential, allow_preview=True) as client, + ): + agent = None + completed = False + try: + agent = await client.agents.create_version( + agent_name=agent_name, definition=helpers["interruption_definition"](model) + ) + async with client.beta.voice_agents.realtime.connect(agent_name=agent_name) as connection: + await helpers["interrupt_reply_async"](connection, turn) + deadline = time.monotonic() + helpers["RECORDING_TIMEOUT"] + conversations = client.beta.voice_agents.conversations + while not turn.stored_item_id: + try: + conversation = await conversations.get(agent_name, turn.conversation_id) + if conversation.status == "failed": + raise RuntimeError("The interrupted conversation failed to persist.") + if conversation.status == "completed": + stored_item_id = helpers["_stored_audio_item"]( + [item async for item in conversations.list_items(agent_name, turn.conversation_id)], + turn.response_id, + ) + if stored_item_id is not None: + turn.stored_item_id = stored_item_id + except HttpResponseError as error: + if not helpers["_recording_pending"](error): + raise + if not turn.stored_item_id: + timeout = helpers["_remaining"](deadline, "stored interrupted conversation item") + await asyncio.sleep(min(1.0, timeout)) + fixture = RealtimeInterruptionFixture( + agent_name, turn.conversation_id, turn.stored_item_id, agent.version + ) + completed = True + return fixture + finally: + if not completed and agent is not None: + await _delete_fixture( + client, + RealtimeInterruptionFixture( + agent_name, turn.conversation_id, turn.stored_item_id, agent.version + ), + ) + + def remove_resource(self, name, **kwargs): + if self.fixture is not None: + asyncio.run(self._cleanup_fixture()) + self.fixture = None + self.endpoint = None + + async def _cleanup_fixture(self) -> None: + fixture, endpoint = self.fixture, self.endpoint + assert fixture is not None and endpoint + credential = self.test_class_instance.get_credential(AIProjectClient, is_async=True) + async with credential, AIProjectClient(endpoint=endpoint, credential=credential, allow_preview=True) as client: + await _delete_fixture(client, fixture) + + +def add_interruption_sanitizers(fixture: RealtimeInterruptionFixture) -> None: + for actual, replacement in ( + (fixture.agent_name, _AGENT), + (fixture.conversation_id, _CONVERSATION), + (fixture.item_id, _ITEM), + ): + add_general_regex_sanitizer(regex=re.escape(actual), value=replacement, function_scoped=True) + + +def assert_generated_status(expected: int | tuple[int, ...]): + def verify(response): + statuses = (expected,) if isinstance(expected, int) else expected + assert response.http_response.status_code in statuses + path = urlsplit(response.http_request.url).path + assert "/protocols/voice/conversations/" in path + assert "/audio/generated" in path + assert response.http_request.headers["Foundry-Features"] == "VoiceAgents=V1Preview" + + return verify + + +def assert_conversation_deleted(response) -> None: + assert response.http_response.status_code == 204 + assert "/protocols/voice/conversations/" in urlsplit(response.http_request.url).path + assert response.http_request.headers["Foundry-Features"] == "VoiceAgents=V1Preview" + + +def assert_generated_metadata(metadata, fixture: RealtimeInterruptionFixture) -> None: + assert isinstance(metadata, models.VoiceGeneratedAudioItem) + assert metadata.conversation_id == fixture.conversation_id and metadata.item_id == fixture.item_id + assert metadata.role == "agent" and metadata.codec == "pcm16" + assert metadata.format == "wav" and metadata.sample_rate == 24000 and metadata.channels == 1 + assert metadata.duration_ms is not None and metadata.duration_ms.total_seconds() > 0 + assert metadata.blob_uri is None, "This recording must exercise the Foundry-managed content route" + + +def assert_generated_wav(content: bytes, metadata, fixture: RealtimeInterruptionFixture) -> None: + assert_generated_metadata(metadata, fixture) + assert_wav(content, metadata) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_live_client.py b/sdk/ai/azure-ai-projects/tests/agents/test_live_client.py new file mode 100644 index 000000000000..375462ba9fbb --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_live_client.py @@ -0,0 +1,1686 @@ +# pylint: disable=too-many-lines +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +# cspell:ignore fsignature Bvalue +"""Deterministic public Live client tests, with only WebSocket transports replaced. + +Both clients use the same wire assertions. No service, recording, real credential, +or audio device is involved; audio payloads are small synthetic byte sequences. +""" + +import asyncio +import base64 +import inspect +import json +import logging +import threading +from collections import UserDict +from collections.abc import AsyncIterator, Iterator, Mapping +from concurrent.futures import ThreadPoolExecutor +from contextlib import asynccontextmanager +from types import MappingProxyType, SimpleNamespace +from typing import Optional, TypeVar, get_args, get_origin, get_type_hints +from unittest.mock import AsyncMock, MagicMock, Mock, patch +from urllib.parse import parse_qs, urlsplit + +import aiohttp +import pytest +import pytest_asyncio +from azure.core.credentials import AccessToken +from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK +from websockets.frames import Close + +from azure.ai.projects import AIProjectClient, __version__, models, operations +from azure.ai.projects._live_utils import _server_event_types +from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient +from azure.ai.projects.aio import operations as async_operations + +_ENDPOINT = "https://fake-account.services.ai.azure.com/api/projects/fake-project" +_HOST = "fake-account.services.ai.azure.com" +_AGENT = "agent-test" +_TOKEN = "unit-test-token" +_SCOPES = ("https://ai.azure.com/.default",) +_SESSION = { + "id": "live-session-test", + "model": "gpt-live-1", + "expires_at": 9_999_999_999, + "status": "active", + "store": False, + "delegation": {"type": "client"}, +} +_STARTED = {"type": "session.started", "event_id": "evt-started", "session": _SESSION} +_CLOSED = { + "type": "session.closed", + "event_id": "evt-closed", + "client_event_id": "evt-close", + "reason": "close_requested", + "session": _SESSION, + "usage": {"seconds": 1.25}, +} + +pytestmark = pytest.mark.asyncio + + +class _FakeCredential: + def __init__(self): + self.calls = [] + self.failure = None + + def get_token(self, *scopes, **kwargs): + self.calls.append((scopes, kwargs)) + if self.failure is not None: + raise self.failure + return AccessToken(_TOKEN, 9_999_999_999) + + +class _AsyncFakeCredential(_FakeCredential): + async def get_token(self, *scopes, **kwargs): + return super().get_token(*scopes, **kwargs) + + +def _message(kind, data=None): + return SimpleNamespace(type=kind, data=data) + + +def _handshake_query(url, kwargs): + query = parse_qs(urlsplit(url).query, keep_blank_values=True) + for name, value in kwargs.get("params", {}).items(): + query.setdefault(name, []).append(value) + return query + + +def _contains_type_variable(annotation): + return isinstance(annotation, TypeVar) or any( + _contains_type_variable(argument) for argument in get_args(annotation) + ) + + +class _Transport: + def __init__(self, is_async): + self.is_async = is_async + self.socket = MagicMock(name="websocket") + self.socket.closed = False + self.socket.close_code = None + self.socket.recv.return_value = json.dumps(_STARTED) + self.socket.receive = AsyncMock(return_value=_message(aiohttp.WSMsgType.TEXT, json.dumps(_STARTED))) + self.socket.send_str = AsyncMock() + self.socket.exception.return_value = None + close = AsyncMock if is_async else Mock + self.socket.close = close(side_effect=self._close_socket) + self.session = MagicMock(name="websocket_session") + self.session.closed = False + self.session.ws_connect = AsyncMock(return_value=self.socket) + self.session.close = AsyncMock(side_effect=self._close_session) + + def _close_socket(self, **kwargs): + self.socket.closed = True + + def _close_session(self): + self.session.closed = True + + @property + def writes(self): + return self.socket.send_str if self.is_async else self.socket.send + + @property + def sent(self): + calls = self.writes.await_args_list if self.is_async else self.writes.call_args_list + return [json.loads(call.args[0]) for call in calls] + + def queue(self, *payloads, binary=False): + frames = [json.dumps(payload) for payload in payloads] + if binary: + frames = [frame.encode("utf-8") for frame in frames] + self.socket.recv.side_effect = frames + kind = aiohttp.WSMsgType.BINARY if binary else aiohttp.WSMsgType.TEXT + self.socket.receive.side_effect = [_message(kind, frame) for frame in frames] + + def raw(self, frame): + self.socket.recv.return_value = frame + kind = aiohttp.WSMsgType.BINARY if isinstance(frame, (bytes, bytearray)) else aiohttp.WSMsgType.TEXT + self.socket.receive.return_value = _message(kind, frame) + + def assert_closed_once(self): + if self.is_async: + self.socket.close.assert_awaited_once() + self.session.close.assert_awaited_once() + assert self.session.closed is True + else: + self.socket.close.assert_called_once() + assert self.socket.closed is True + + +class _LiveHarness: + def __init__(self, is_async): + self.is_async = is_async + self.credential = _AsyncFakeCredential() if is_async else _FakeCredential() + self.transport = _Transport(is_async) + self.connect = Mock(return_value=self.transport.socket) + self.session_factory = Mock(return_value=self.transport.session) + self.clients = [] + self.client = self.new_client(allow_preview=True) + + def new_client(self, **options): + options.setdefault("endpoint", _ENDPOINT) + options.setdefault("credential", self.credential) + client_type = AsyncAIProjectClient if self.is_async else AIProjectClient + client = client_type(**options) + self.clients.append(client) + return client + + @property + def live(self): + return self.client.beta.voice_agents.live + + @property + def handshake(self): + call = self.transport.session.ws_connect.await_args if self.is_async else self.connect.call_args + assert call is not None + return call.args[0], call.kwargs + + @property + def headers(self): + return self.handshake[1]["headers" if self.is_async else "additional_headers"] + + def manager(self, *, protocol="live", **options): + options.setdefault("agent_name", _AGENT) + return getattr(self.client.beta.voice_agents, protocol).connect(**options) + + async def call(self, method, *args, **kwargs): + result = method(*args, **kwargs) + return await result if self.is_async else result + + async def exit(self, manager): + method = manager.__aexit__ if self.is_async else manager.__exit__ + await self.call(method, None, None, None) + + async def collect(self, connection): + if self.is_async: + return [event async for event in connection] + return list(connection) + + @asynccontextmanager + async def open(self, *, protocol="live", **options): + manager = self.manager(protocol=protocol, **options) + if self.is_async: + async with manager as connection: + yield connection + else: + with manager as connection: + yield connection + + +@pytest.fixture(params=[False, True], ids=["sync", "async"]) +def is_async(request): + return request.param + + +@pytest_asyncio.fixture +async def live(is_async, monkeypatch): + harness = _LiveHarness(is_async) + monkeypatch.setattr("websockets.sync.client.connect", harness.connect) + monkeypatch.setattr("aiohttp.ClientSession", harness.session_factory) + try: + yield harness + finally: + for client in reversed(harness.clients): + await harness.call(client.close) + + +async def test_live_is_public_and_connect_is_lazy(live): + public_operations = async_operations if live.is_async else operations + prefix = "Async" if live.is_async else "" + assert isinstance(live.live, getattr(public_operations, f"{prefix}BetaLive")) + assert live.live is live.client.beta.voice_agents.live + assert live.live is not live.client.beta.voice_agents.realtime + assert tuple(inspect.signature(type(live.live).__init__).parameters) == ("self", "args", "kwargs") + + manager = live.manager() + assert isinstance(manager, getattr(public_operations, f"{prefix}BetaLiveConnectionManager")) + assert live.credential.calls == [] + live.connect.assert_not_called() + live.session_factory.assert_not_called() + + connection = await live.call(manager.enter) + try: + assert isinstance(connection, getattr(public_operations, f"{prefix}BetaLiveConnection")) + assert connection.closed is False + assert "open" in repr(connection) + live.transport.writes.assert_not_called() + finally: + await live.exit(manager) + live.transport.assert_closed_once() + assert "closed" in repr(connection) + + +async def test_connect_signature_has_only_live_options(live): + parameters = inspect.signature(live.live.connect).parameters + assert tuple(parameters) == ( + "agent_name", + "agent_version", + "structured_inputs", + "store", + "connection_url", + "api_version", + "credential_scopes", + "extra_query", + "extra_headers", + "kwargs", + ) + assert parameters["agent_name"].default is inspect.Parameter.empty + for name, parameter in parameters.items(): + if name == "kwargs": + assert parameter.kind is inspect.Parameter.VAR_KEYWORD + else: + assert parameter.kind is inspect.Parameter.KEYWORD_ONLY + if name != "agent_name": + assert parameter.default is None + assert "model" not in parameters + assert "transport" not in parameters + assert models.LiveServerEvent.__mapping__ + + +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +@pytest.mark.parametrize("member", ["enter", "recv", "send", "iterator"]) +async def test_public_websocket_signatures_have_concrete_type_hints(is_async, protocol, member): + public_operations = async_operations if is_async else operations + prefix = f"{'Async' if is_async else ''}Beta{protocol.capitalize()}" + connection_type = getattr(public_operations, f"{prefix}Connection") + manager_type = getattr(public_operations, f"{prefix}ConnectionManager") + client_event = getattr(public_operations, "LiveClientEvent" if protocol == "live" else "ClientEvent") + server_event = getattr(public_operations, "LiveServerEvent" if protocol == "live" else "ServerEvent") + owner = manager_type if member == "enter" else connection_type + method_name = ("__aiter__" if is_async else "__iter__") if member == "iterator" else member + method = getattr(owner, method_name) + parameters = inspect.signature(method).parameters + hints = get_type_hints(method) + + assert hints, f"{owner.__name__}.{method_name} must retain public annotations" + assert not any( + _contains_type_variable(annotation) for annotation in hints.values() + ), f"{owner.__name__}.{method_name} exposes unresolved generic type variables" + assert "return" in hints + + if member == "enter": + assert tuple(parameters) == ("self",) + assert hints == {"return": connection_type} + elif member == "recv": + assert hints["return"] == server_event + if is_async: + assert tuple(parameters) == ("self",) + assert set(hints) == {"return"} + else: + assert tuple(parameters) == ("self", "timeout") + assert parameters["timeout"].kind is inspect.Parameter.KEYWORD_ONLY + assert parameters["timeout"].default is None + assert hints["timeout"] == Optional[float] + assert set(hints) == {"timeout", "return"} + elif member == "send": + assert tuple(parameters) == ("self", "event") + assert parameters["event"].kind is inspect.Parameter.POSITIONAL_OR_KEYWORD + assert parameters["event"].default is inspect.Parameter.empty + assert hints == {"event": client_event, "return": type(None)} + else: + assert tuple(parameters) == ("self",) + assert set(hints) == {"return"} + assert get_origin(hints["return"]) is (AsyncIterator if is_async else Iterator) + assert get_args(hints["return"]) == (server_event,) + + +@pytest.mark.parametrize("preview", [None, False], ids=["default", "false"]) +async def test_beta_namespace_implies_preview_opt_in_without_allow_preview(live, preview): + options = {} if preview is None else {"allow_preview": preview} + client = live.new_client(**options) + manager = client.beta.voice_agents.live.connect(agent_name=_AGENT) + assert live.credential.calls == [] + live.connect.assert_not_called() + live.session_factory.assert_not_called() + + connection = await live.call(manager.enter) + try: + assert connection.closed is False + assert live.headers["Foundry-Features"] == "VoiceAgents=V1Preview" + assert live.headers["Authorization"] == f"Bearer {_TOKEN}" + assert live.credential.calls == [(_SCOPES, {})] + live.transport.writes.assert_not_called() + if live.is_async: + live.transport.session.ws_connect.assert_awaited_once() + else: + live.connect.assert_called_once() + finally: + await live.exit(manager) + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("mapping_type", [dict, MappingProxyType, UserDict]) +async def test_handshake_encodes_live_route_authentication_and_all_options(live, mapping_type): + structured_inputs = mapping_type({"name": "Zoë / guest", "count": 0, "enabled": False, "optional": None}) + extra_query = MappingProxyType({"custom": "space + /?&=#"}) + extra_headers = MappingProxyType({"X-Custom": "example"}) + options = {"heartbeat": 3, "max_msg_size": 1024} if live.is_async else {"open_timeout": 3, "max_size": 1024} + scopes = ["https://scope-one.example/.default", "https://scope-two.example/.default"] + async with live.open( + agent_name="name /?#% 雪", + agent_version="7", + structured_inputs=structured_inputs, + store=False, + api_version="live-test-version", + credential_scopes=scopes, + extra_query=extra_query, + extra_headers=extra_headers, + **options, + ): + url, kwargs = live.handshake + assert urlsplit(url).path == ( + "/api/projects/fake-project/agents/name%20%2F%3F%23%25%20%E9%9B%AA" + "/endpoint/protocols/voice/live/sessions" + ) + assert urlsplit(url).scheme == "wss" + assert urlsplit(url).netloc == _HOST + query = _handshake_query(url, kwargs) + user_agent = live.headers["User-Agent"] + assert f"azsdk-python-ai-projects/{__version__}" in user_agent + assert query == { + "api-version": ["live-test-version"], + "x-ms-client-sdk": [user_agent], + "agent_version_override": ["7"], + "structured_inputs": [query["structured_inputs"][0]], + "store": ["false"], + "custom": ["space + /?&=#"], + } + assert json.loads(query["structured_inputs"][0]) == structured_inputs + assert live.headers == { + "Authorization": f"Bearer {_TOKEN}", + "Foundry-Features": "VoiceAgents=V1Preview", + "User-Agent": user_agent, + "X-Custom": "example", + } + assert live.credential.calls == [(tuple(scopes), {})] + assert all(kwargs[name] == value for name, value in options.items()) + assert not kwargs.get("protocols" if live.is_async else "subprotocols") + assert "Sec-WebSocket-Protocol" not in live.headers + assert "model" not in query + assert "transport" not in query + assert "model" not in kwargs + assert "transport" not in kwargs + if not live.is_async: + assert kwargs["user_agent_header"] is None + live.transport.writes.assert_not_called() + assert dict(extra_query) == {"custom": "space + /?&=#"} + assert dict(extra_headers) == {"X-Custom": "example"} + assert structured_inputs == {"name": "Zoë / guest", "count": 0, "enabled": False, "optional": None} + live.transport.assert_closed_once() + + +async def test_defaults_do_not_add_model_transport_startup_or_optional_query(live): + async with live.open(): + url, kwargs = live.handshake + assert urlsplit(url).path.endswith(f"/agents/{_AGENT}/endpoint/protocols/voice/live/sessions") + assert set(_handshake_query(url, kwargs)) == {"api-version", "x-ms-client-sdk"} + assert live.credential.calls == [(_SCOPES, {})] + assert not kwargs.get("protocols" if live.is_async else "subprotocols") + live.transport.writes.assert_not_called() + + +@pytest.mark.parametrize("header_name", ["User-Agent", "user-agent", "uSeR-aGeNt"]) +async def test_caller_user_agent_is_respected_case_insensitively(live, header_name): + headers = {header_name: "custom-test-client"} + async with live.open(extra_headers=headers): + matching = [(name, value) for name, value in live.headers.items() if name.lower() == "user-agent"] + assert matching == [(header_name, "custom-test-client")] + query = _handshake_query(*live.handshake) + assert f"azsdk-python-ai-projects/{__version__}" in query["x-ms-client-sdk"][0] + assert headers == {header_name: "custom-test-client"} + + +@pytest.mark.parametrize("authority", [_HOST, f"{_HOST.upper()}:443"]) +async def test_same_origin_override_preserves_opaque_query_and_caller_mappings(live, authority): + override = ( + f"wss://{authority}/custom/live" "?sig=opaque%2fsignature%2Bvalue%3D&keep=one&keep=two&empty=&path=folder%2F" + ) + query = {"custom": "space + /?&=#"} + headers = {"X-Custom": "unchanged"} + async with live.open(connection_url=override, extra_query=query, extra_headers=headers): + url, kwargs = live.handshake + assert url == override if live.is_async else url.startswith(override + "&") + parsed = _handshake_query(url, kwargs) + assert parsed["sig"] == ["opaque/signature+value="] + assert parsed["keep"] == ["one", "two"] + assert parsed["empty"] == [""] + assert parsed["path"] == ["folder/"] + assert parsed["custom"] == ["space + /?&=#"] + assert url.count("?") == 1 + assert "sig=opaque%2fsignature%2Bvalue%3D" in url + assert "path=folder%2F" in url + assert query == {"custom": "space + /?&=#"} + assert headers == {"X-Custom": "unchanged"} + + +@pytest.mark.parametrize( + "override", + [ + "wss://untrusted.example/custom", + f"wss://{_HOST}:8443/custom", + f"ws://{_HOST}/custom", + f"ws://{_HOST}:443/custom", + f"https://{_HOST}/custom", + f"http://{_HOST}:443/custom", + f"wss://{_HOST}:invalid/custom", + "not-a-url", + "", + ], +) +async def test_invalid_override_fails_before_token_or_transport(live, override): + manager = live.manager(connection_url=override) + with pytest.raises(ValueError): + await live.call(manager.enter) + assert live.credential.calls == [] + live.connect.assert_not_called() + live.session_factory.assert_not_called() + + +@pytest.mark.parametrize("endpoint", [f"http://{_HOST}/project", f"ftp://{_HOST}/project"]) +async def test_insecure_computed_endpoint_fails_before_token_or_transport(live, endpoint): + client = live.new_client(endpoint=endpoint, allow_preview=True) + manager = client.beta.voice_agents.live.connect(agent_name=_AGENT) + with pytest.raises(ValueError, match="wss"): + await live.call(manager.enter) + assert live.credential.calls == [] + live.connect.assert_not_called() + live.session_factory.assert_not_called() + + +@pytest.mark.parametrize( + "structured_inputs,extra_query", + [ + ({"name": "guest"}, {"structured_input": "{}"}), + (None, {"structured_inputs": "{}", "structured_input": "{}"}), + ({}, {"structured_inputs": "{}", "structured_input": "{}"}), + ], +) +async def test_structured_input_spellings_are_mutually_exclusive_before_auth(live, structured_inputs, extra_query): + manager = live.manager(structured_inputs=structured_inputs, extra_query=extra_query) + with pytest.raises(ValueError, match="structured_input.*structured_inputs"): + await live.call(manager.enter) + assert live.credential.calls == [] + live.connect.assert_not_called() + live.session_factory.assert_not_called() + assert "structured_input" in extra_query + + +@pytest.mark.parametrize("name", ["structured_input", "structured_inputs"]) +async def test_one_explicit_structured_input_query_spelling_is_preserved(live, name): + query = {name: '{"name": "guest"}'} + async with live.open(extra_query=query): + values = _handshake_query(*live.handshake) + assert values[name] == ['{"name": "guest"}'] + assert ("structured_inputs" if name == "structured_input" else "structured_input") not in values + assert query == {name: '{"name": "guest"}'} + + +@pytest.mark.parametrize("store", [True, False]) +async def test_typed_query_options_override_extra_query_without_mutating_it(live, store): + extra_query = { + "agent_version_override": "old-version", + "structured_inputs": '{"old":true}', + "store": "old-store", + } + async with live.open(agent_version="8", structured_inputs={}, store=store, extra_query=extra_query): + query = _handshake_query(*live.handshake) + assert query["agent_version_override"] == ["8"] + assert "x-agent-version-override" not in query + assert query["structured_inputs"] == ["{}"] + assert query["store"] == [str(store).lower()] + assert extra_query == { + "agent_version_override": "old-version", + "structured_inputs": '{"old":true}', + "store": "old-store", + } + + +async def test_manager_snapshots_extra_query_and_headers(live): + extra_query = {"custom": "original"} + extra_headers = {"X-Custom": "original"} + manager = live.manager(extra_query=extra_query, extra_headers=extra_headers) + extra_query["custom"] = "changed" + extra_headers["X-Custom"] = "changed" + await live.call(manager.enter) + try: + assert _handshake_query(*live.handshake)["custom"] == ["original"] + assert live.headers["X-Custom"] == "original" + finally: + await live.exit(manager) + + +async def test_optional_dependency_is_only_required_on_enter(live): + modules = {"aiohttp": None} if live.is_async else {"websockets.sync.client": None, "websockets.typing": None} + dependency = "aiohttp" if live.is_async else "websockets" + with patch.dict("sys.modules", modules): + client = live.new_client(allow_preview=True) + manager = client.beta.voice_agents.live.connect(agent_name=_AGENT) + assert live.credential.calls == [] + with pytest.raises(RuntimeError, match=f"pip install {dependency}") as caught: + await live.call(manager.enter) + assert "live" in str(caught.value).lower() + assert "realtime" not in str(caught.value).lower() + live.connect.assert_not_called() + live.session_factory.assert_not_called() + assert live.credential.calls == [] + + +async def test_token_failure_propagates_without_opening_websocket_or_leaking_session(live): + failure = RuntimeError("fake credential rejected the scope") + live.credential.failure = failure + with pytest.raises(RuntimeError) as caught: + await live.call(live.manager().enter) + assert caught.value is failure + assert live.credential.calls == [(_SCOPES, {})] + live.connect.assert_not_called() + if live.is_async: + live.transport.session.ws_connect.assert_not_awaited() + assert live.session_factory.call_count <= 1 + assert live.transport.session.close.await_count == live.session_factory.call_count + else: + live.session_factory.assert_not_called() + + +@pytest.mark.parametrize( + "failure,expected", + [ + (OSError("upgrade refused"), ConnectionError), + (ValueError("invalid websocket option"), ValueError), + (RuntimeError("websocket already closing"), RuntimeError), + ], +) +async def test_handshake_errors_preserve_causes_and_release_owned_resources(live, failure, expected): + connector = live.transport.session.ws_connect if live.is_async else live.connect + connector.side_effect = failure + manager = live.manager() + with pytest.raises(expected) as caught: + await live.call(manager.enter) + if expected is ConnectionError: + assert caught.value.__cause__ is failure + assert _AGENT in str(caught.value) + assert "live" in str(caught.value).lower() + assert "realtime" not in str(caught.value).lower() + else: + assert caught.value is failure + if live.is_async: + live.transport.session.close.assert_awaited_once() + live.transport.socket.close.assert_not_awaited() + await live.exit(manager) + await live.exit(manager) + if live.is_async: + live.transport.session.close.assert_awaited_once() + + +async def test_live_does_not_negotiate_realtime_even_with_caller_protocol_override(live): + option = "protocols" if live.is_async else "subprotocols" + async with live.open(**{option: ["realtime"]}): + assert not live.handshake[1].get(option) + assert "Sec-WebSocket-Protocol" not in live.headers + + +@pytest.mark.parametrize("kind", ["model", "mapping", "mapping_proxy", "user_dict", "json"]) +async def test_raw_send_supports_generated_model_mapping_and_exact_json(live, kind): + expected = {"type": "response.create", "event_id": "evt-response"} + raw = '{ "type": "response.create", "event_id": "evt-response" }' + event = { + "model": models.LiveClientEventLiveResponseCreateParam(event_id="evt-response"), + "mapping": expected, + "mapping_proxy": MappingProxyType(expected), + "user_dict": UserDict(expected), + "json": raw, + }[kind] + async with live.open() as connection: + await live.call(connection.send, event) + assert live.transport.sent == [expected] + if kind == "json": + live.transport.writes.assert_called_once_with(raw) + assert expected == {"type": "response.create", "event_id": "evt-response"} + + +async def test_generated_session_start_is_available_only_when_explicitly_sent(live): + event = models.LiveSessionStartEvent( + session=models.LiveSessionCreateParams(model="gpt-live-1", store=False), + event_id="evt-raw-start", + ) + async with live.open() as connection: + live.transport.writes.assert_not_called() + await live.call(connection.send, event) + assert live.transport.sent == [ + { + "type": "session.start", + "event_id": "evt-raw-start", + "session": {"model": "gpt-live-1", "store": False}, + } + ] + + +@pytest.mark.parametrize("raw", ["not-json", '{"type":', ""]) +async def test_invalid_outgoing_json_never_reaches_socket(live, raw): + async with live.open() as connection: + with pytest.raises(ValueError, match="not valid JSON"): + await live.call(connection.send, raw) + live.transport.writes.assert_not_called() + assert connection.closed is False + + +@pytest.mark.parametrize("raw", ["null", "[]", '"future-value"', "true", "42", '{"type":[]}']) +async def test_valid_json_values_match_realtime_pass_through_behavior(live, raw): + async with live.open() as connection: + await live.call(connection.send, raw) + live.transport.writes.assert_called_once_with(raw) + assert live.transport.sent == [json.loads(raw)] + assert connection.closed is False + + +async def test_unserializable_mapping_is_rejected_before_socket_write(live): + async with live.open() as connection: + with pytest.raises(TypeError): + await live.call(connection.send, {"type": "response.create", "future": object()}) + live.transport.writes.assert_not_called() + assert connection.closed is False + + +@pytest.mark.parametrize("audio", [b"\x00\x01\xfe\xff", "AAH+/w==", b"", ""]) +@pytest.mark.parametrize("event_id", [None, "evt-audio"]) +async def test_input_audio_append_encodes_bytes_once_and_preserves_base64(live, audio, event_id): + expected = { + "type": "session.input_audio.append", + "audio": base64.b64encode(audio).decode("ascii") if isinstance(audio, bytes) else audio, + } + if event_id is not None: + expected["event_id"] = event_id + async with live.open() as connection: + await live.call(connection.session.input_audio.append, audio=audio, event_id=event_id) + assert live.transport.sent == [expected] + + +async def test_input_audio_mute_and_unmute_emit_only_live_commands(live): + async with live.open() as connection: + await live.call(connection.session.input_audio.mute, event_id="evt-mute") + await live.call(connection.session.input_audio.unmute) + assert live.transport.sent == [ + {"type": "session.input_audio.mute", "event_id": "evt-mute"}, + {"type": "session.input_audio.unmute"}, + ] + + +@pytest.mark.parametrize("resource", ["instructions", "thinking", "commentary"]) +@pytest.mark.parametrize("delegation_id", [None, "delegation-test"]) +@pytest.mark.parametrize("event_id", [None, "evt-text"]) +async def test_text_append_preserves_required_nullable_delegation_on_wire(live, resource, delegation_id, event_id): + expected = { + "type": f"session.{resource}.append", + "content": "Context for the Live model.", + "delegation_id": delegation_id, + } + if event_id is not None: + expected["event_id"] = event_id + async with live.open() as connection: + await live.call( + getattr(connection.session, resource).append, + content="Context for the Live model.", + delegation_id=delegation_id, + event_id=event_id, + ) + assert live.transport.sent == [expected] + assert "delegation_id" in live.transport.sent[0] + + +@pytest.mark.parametrize("resource", ["instructions", "thinking", "commentary"]) +async def test_text_append_cannot_omit_delegation_id(live, resource): + async with live.open() as connection: + append = getattr(connection.session, resource).append + parameter = inspect.signature(append).parameters["delegation_id"] + assert parameter.kind is inspect.Parameter.KEYWORD_ONLY + assert parameter.default is inspect.Parameter.empty + with pytest.raises(TypeError, match="delegation_id"): + await live.call(append, content="Context without a delegation argument") + live.transport.writes.assert_not_called() + + +@pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) +async def test_session_update_serializes_sparse_delegation_settings(live, typed): + settings = { + "delegation": { + "type": "responses", + "responses": { + "instructions": "Answer concisely.", + "parallel_tool_calls": False, + "max_output_tokens": 32, + }, + } + } + session = ( + models.LiveSessionUpdateParams( + delegation=models.LiveResponsesDelegationUpdateParam( + responses=models.LiveResponsesDelegationSettingsUpdateInputParam( + instructions="Answer concisely.", parallel_tool_calls=False, max_output_tokens=32 + ) + ) + ) + if typed + else settings + ) + async with live.open() as connection: + await live.call(connection.session.update, session=session, event_id="evt-update") + assert live.transport.sent == [{"type": "session.update", "event_id": "evt-update", "session": settings}] + assert "model" not in settings + assert "audio" not in settings + + +async def test_session_update_uses_native_client_delegation_model(live): + settings = models.LiveSessionUpdateParams( + delegation=models.LiveSessionUpdateParamsDelegationLiveClientDelegationParam(acknowledgement_delay_ms=0) + ) + expected = {"delegation": {"type": "client", "acknowledgement_delay_ms": 0}} + async with live.open() as connection: + await live.call(connection.session.update, session=settings) + assert live.transport.sent == [{"type": "session.update", "session": expected}] + restored = models.LiveSessionUpdateParams(expected) + assert isinstance(restored.delegation, models.LiveSessionUpdateParamsDelegationLiveClientDelegationParam) + assert restored.as_dict() == expected + + +@pytest.mark.parametrize( + "item", + [ + { + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": "Check this itinerary."}], + }, + { + "type": "function_call_output", + "call_id": "call-test", + "output": '{"available":false,"count":0}', + }, + ], + ids=["message", "function-result"], +) +async def test_response_item_create_preserves_responses_item_mapping(live, item): + expected = json.loads(json.dumps(item)) + async with live.open() as connection: + await live.call(connection.response.item.create, item=MappingProxyType(item), event_id="evt-item") + assert live.transport.sent == [{"type": "response.item.create", "event_id": "evt-item", "item": expected}] + assert item == expected + + +@pytest.mark.parametrize("event_id", [None, "evt-create"]) +async def test_response_create_has_only_event_id_and_no_cancel_helper(live, event_id): + async with live.open() as connection: + assert tuple(inspect.signature(connection.response.create).parameters) == ("event_id",) + assert not hasattr(connection.response, "cancel") + await live.call(connection.response.create, event_id=event_id) + expected = {"type": "response.create"} + if event_id is not None: + expected["event_id"] = event_id + assert live.transport.sent == [expected] + + +async def test_session_close_requests_shutdown_without_closing_transport(live): + live.transport.queue(_STARTED, _CLOSED) + async with live.open() as connection: + started = await live.call(connection.recv) + assert isinstance(started, models.LiveServerEventLiveSessionStarted) + assert isinstance(started.session, models.VoiceAgentLiveSessionResource) + assert started.session.id == "live-session-test" + assert isinstance(started.session.delegation, Mapping) + assert started.session.delegation["type"] == "client" + assert started.as_dict() == _STARTED + await live.call(connection.session.close, event_id="evt-close") + assert live.transport.sent == [{"type": "session.close", "event_id": "evt-close"}] + assert connection.closed is False + live.transport.socket.close.assert_not_called() + closed = await live.call(connection.recv) + assert isinstance(closed, models.LiveServerEventLiveSessionClosed) + assert closed.reason == "close_requested" + assert closed.client_event_id == "evt-close" + assert closed.session.status == "active" + assert isinstance(closed.usage, models.LiveSessionUsage) + assert closed.usage.seconds == 1.25 + assert closed.as_dict() == _CLOSED + assert connection.closed is False + live.transport.socket.close.assert_not_called() + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("invalid", [None, "not-a-model", 42, object, models.LiveServerEvent({"type": "future.event"})]) +async def test_live_event_registry_accepts_only_model_classes(invalid): + registry = {"session.started": models.LiveServerEventLiveSessionStarted, "invalid": invalid} + + assert _server_event_types(registry) == {"session.started": models.LiveServerEventLiveSessionStarted} + + +@pytest.mark.parametrize( + "event_type,event_model", + list(models.LiveServerEvent.__mapping__.items()), + ids=list(models.LiveServerEvent.__mapping__), +) +async def test_every_generated_live_server_event_is_dispatched(live, event_type, event_model): + payload = {"type": event_type, "event_id": "evt-dispatch", "future_field": {"enabled": False}} + live.transport.queue(payload) + async with live.open() as connection: + event = await live.call(connection.recv) + assert type(event) is event_model + assert isinstance(event, models.LiveServerEvent) + assert event.type == event_type + assert event.as_dict() == payload + + +@pytest.mark.parametrize("frame_type", [bytes, bytearray], ids=["bytes", "bytearray"]) +async def test_binary_json_audio_event_uses_generated_base64_string_field(live, frame_type): + payload = {"type": "session.output_audio.delta", "delta": "AAH+/w==", "start_ms": 0, "end_ms": 20} + live.transport.raw(frame_type(json.dumps(payload).encode("utf-8"))) + async with live.open() as connection: + event = await live.call(connection.recv) + assert isinstance(event, models.LiveOutputAudioDelta) + assert isinstance(event.delta, str) + assert base64.b64decode(event.delta) == b"\x00\x01\xfe\xff" + assert (event.start_ms, event.end_ms) == (0, 20) + assert event.as_dict() == payload + + +async def test_reflected_audio_and_transcript_fields_are_not_realtime_aliases(live): + reflected = {"type": "session.input_audio.append", "audio": "AAH+/w=="} + transcript = { + "type": "session.output_transcript.delta", + "event_id": "evt-transcript", + "client_event_id": "evt-client", + "delta": "A synthetic transcript.", + "start_ms": 5, + "end_ms": 15, + } + live.transport.queue(reflected, transcript) + async with live.open() as connection: + audio = await live.call(connection.recv) + text = await live.call(connection.recv) + assert isinstance(audio, models.LiveInputAudioAppend) + assert audio.audio == "AAH+/w==" + assert isinstance(text, models.LiveServerEventLiveOutputTranscriptDelta) + assert text.delta == "A synthetic transcript." + assert (text.start_ms, text.end_ms) == (5, 15) + assert audio.as_dict() == reflected + assert text.as_dict() == transcript + + +async def test_delegation_and_wrapped_responses_events_retain_full_wire_shape(live): + delegation = { + "type": "session.delegation.created", + "event_id": "evt-delegation", + "offset_ms": 20, + "delegation": { + "id": "delegation-test", + "type": "delegation", + "target": "responses", + "response_id": "response-test", + }, + } + response = { + "type": "response.event", + "event_id": "evt-response-event", + "client_event_id": "evt-response-create", + "delegation_id": "delegation-test", + "event": { + "type": "response.function_call_arguments.done", + "call_id": "call-test", + "arguments": '{"city":"Seattle"}', + "future": {"preserved": True}, + }, + } + live.transport.queue(delegation, response) + async with live.open() as connection: + created = await live.call(connection.recv) + wrapped = await live.call(connection.recv) + assert isinstance(created, models.LiveServerEventLiveDelegationCreated) + assert isinstance(created.delegation, models.VoiceAgentLiveDelegationItem) + assert created.delegation.id == "delegation-test" + assert created.delegation.response_id == "response-test" + assert isinstance(wrapped, models.LiveServerEventLiveResponseEvent) + assert wrapped.delegation_id == "delegation-test" + assert wrapped.event == response["event"] + assert created.as_dict() == delegation + assert wrapped.as_dict() == response + + +async def test_foundry_managed_ownership_survives_public_live_event_parsing(live): + owner = { + "type": "foundry_managed_agent", + "agent_name": "prompt-agent-test", + "agent_version": "7", + } + session = dict(_SESSION, delegation=owner) + payloads = [ + dict(_STARTED, session=session, conversation_id="conversation-test"), + {"type": "session.updated", "event_id": "evt-updated", "session": session}, + { + "type": "session.delegation.created", + "event_id": "evt-delegation", + "offset_ms": 20, + "delegation": { + "type": "delegation", + "id": "delegation-test", + "target": "foundry_managed_agent", + }, + }, + dict(_CLOSED, session=session), + ] + event_models = [ + models.LiveServerEventLiveSessionStarted, + models.LiveServerEventLiveSessionUpdated, + models.LiveServerEventLiveDelegationCreated, + models.LiveServerEventLiveSessionClosed, + ] + live.transport.queue(*payloads) + + async with live.open() as connection: + for payload, event_model in zip(payloads, event_models): + event = await live.call(connection.recv) + assert isinstance(event, event_model) + if isinstance(event, models.LiveServerEventLiveDelegationCreated): + assert isinstance(event.delegation, models.VoiceAgentLiveDelegationItem) + assert event.delegation.target == "foundry_managed_agent" + else: + assert isinstance( + event, + ( + models.LiveServerEventLiveSessionStarted, + models.LiveServerEventLiveSessionUpdated, + models.LiveServerEventLiveSessionClosed, + ), + ) + assert isinstance(event.session, models.VoiceAgentLiveSessionResource) + assert isinstance(event.session.delegation, Mapping) + assert dict(event.session.delegation) == owner + assert event.as_dict() == payload + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("event_type", ["future.live.event", None, 1, False, [], {}]) +async def test_unknown_or_non_string_event_type_returns_unchanged_mapping(live, event_type): + payload = {"type": event_type, "future": {"text": "preserved", "optional": None}} + live.transport.queue(payload, {"future": ["missing", "type"]}) + async with live.open() as connection: + assert await live.call(connection.recv) == payload + assert await live.call(connection.recv) == {"future": ["missing", "type"]} + assert connection.closed is False + + +async def test_server_error_is_returned_as_typed_error_not_success_or_swallowed(live): + payload = { + "type": "error", + "event_id": "evt-server-error", + "client_event_id": "evt-request", + "error": { + "type": "invalid_request_error", + "code": "invalid_delegation", + "message": "The delegation does not exist.", + "param": "delegation_id", + "client_event_id": "evt-request", + }, + } + live.transport.queue(payload, _STARTED) + async with live.open() as connection: + event = await live.call(connection.recv) + assert isinstance(event, models.LiveServerEventLiveErrorEvent) + assert isinstance(event.error, models.LiveLiveError) + assert event.error.code == "invalid_delegation" + assert event.error.message == "The delegation does not exist." + assert event.client_event_id == "evt-request" + assert event.as_dict() == payload + assert connection.closed is False + assert isinstance(await live.call(connection.recv), models.LiveServerEventLiveSessionStarted) + + +@pytest.mark.parametrize("raw,exception", [("{invalid", ValueError), (b"\xff", UnicodeDecodeError)]) +async def test_invalid_incoming_frame_is_not_replaced_with_success(live, raw, exception): + live.transport.raw(raw) + async with live.open() as connection: + with pytest.raises(exception): + await live.call(connection.recv) + assert connection.closed is False + live.transport.writes.assert_not_called() + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +@pytest.mark.parametrize("payload", [None, [], [{"type": "session.started"}], "session.started", 0, True]) +@pytest.mark.parametrize("binary", [False, True], ids=["text", "binary"]) +async def test_incoming_non_object_json_raises_value_error_without_poisoning_connection( + live, protocol, payload, binary +): + next_payload = _STARTED if protocol == "live" else {"type": "session.created", "session": {}} + live.transport.queue(payload, next_payload, binary=binary) + async with live.open(protocol=protocol) as connection: + with pytest.raises(ValueError): + await live.call(connection.recv) + assert connection.closed is False + live.transport.socket.close.assert_not_called() + event = await live.call(connection.recv) + expected_type = ( + models.LiveServerEventLiveSessionStarted if protocol == "live" else models.RealtimeServerEventSessionCreated + ) + assert isinstance(event, expected_type) + assert event.as_dict() == next_payload + live.transport.writes.assert_not_called() + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("fail_in_body", [False, True], ids=["normal", "exception"]) +async def test_context_manager_releases_transport_and_preserves_body_exception(live, fail_in_body): + failure = RuntimeError("application failed") + try: + async with live.open() as connection: + if fail_in_body: + raise failure + except RuntimeError as caught: + assert fail_in_body + assert caught is failure + else: + assert not fail_in_body + assert connection.closed is True + live.transport.assert_closed_once() + + +async def test_explicit_close_is_idempotent_and_forwards_code_and_reason(live): + manager = live.manager() + connection = await live.call(manager.enter) + try: + await live.call(connection.close, code=1001, reason="finished ✓") + assert connection.closed is True + await live.call(connection.close) + finally: + await live.exit(manager) + await live.exit(manager) + live.transport.assert_closed_once() + expected = {"code": 1001} + expected["message" if live.is_async else "reason"] = "finished ✓".encode("utf-8") if live.is_async else "finished ✓" + live.transport.socket.close.assert_called_once_with(**expected) + live.transport.writes.assert_not_called() + + +async def test_connection_itself_is_a_context_manager(live): + manager = live.manager() + connection = await live.call(manager.enter) + try: + if live.is_async: + async with connection as entered: + assert entered is connection + else: + with connection as entered: + assert entered is connection + assert connection.closed is True + finally: + await live.exit(manager) + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_task_cancellation_inside_connection_context_releases_resources(live, protocol): + entered = asyncio.Event() + block = asyncio.Event() + + async def use_connection(): + async with live.open(protocol=protocol): + entered.set() + await block.wait() + + task = asyncio.create_task(use_connection()) + try: + await asyncio.wait_for(entered.wait(), timeout=2) + finally: + task.cancel() + with pytest.raises(asyncio.CancelledError): + await task + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +@pytest.mark.parametrize("blocked_resource", ["websocket", "http_session"]) +@pytest.mark.parametrize("cancel_caller", [None, "first_close", "context_exit"]) +async def test_async_close_callers_wait_for_shared_cancellation_safe_cleanup( + live, protocol, blocked_resource, cancel_caller +): + blocked = asyncio.Event() + release = asyncio.Event() + + async def close_socket(**kwargs): + if blocked_resource == "websocket": + blocked.set() + await release.wait() + live.transport.socket.closed = True + + async def close_session(): + if blocked_resource == "http_session": + blocked.set() + await release.wait() + live.transport.session.closed = True + + live.transport.socket.close.side_effect = close_socket + live.transport.session.close.side_effect = close_session + manager = live.manager(protocol=protocol) + connection = await manager.enter() + callers = {"first_close": asyncio.create_task(connection.close(code=1001, reason="first caller"))} + try: + await asyncio.wait_for(blocked.wait(), timeout=2) + callers["second_close"] = asyncio.create_task(connection.close(code=1000, reason="second caller")) + callers["context_exit"] = asyncio.create_task(live.exit(manager)) + callers["second_context_exit"] = asyncio.create_task(live.exit(manager)) + await asyncio.sleep(0) + assert all(not caller.done() for caller in callers.values()) + assert live.transport.session.closed is False + if cancel_caller is not None: + for _ in range(2): + callers[cancel_caller].cancel() + await asyncio.sleep(0) + assert all(not caller.done() for caller in callers.values()) + release.set() + results = await asyncio.wait_for(asyncio.gather(*callers.values(), return_exceptions=True), timeout=2) + for name, result in zip(callers, results): + if name == cancel_caller: + assert isinstance(result, asyncio.CancelledError) + else: + assert result is None + finally: + release.set() + await asyncio.wait_for(asyncio.gather(*callers.values(), return_exceptions=True), timeout=2) + await live.exit(manager) + live.transport.assert_closed_once() + live.transport.socket.close.assert_awaited_once_with(code=1001, message=b"first caller") + assert manager._connection is None + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +@pytest.mark.parametrize("failure_source", ["websocket", "http_session"]) +async def test_async_close_failure_propagates_to_every_waiter_without_repeating_cleanup(live, protocol, failure_source): + blocked = asyncio.Event() + release = asyncio.Event() + failure = OSError("offline cleanup failure") + + async def close_socket(**kwargs): + blocked.set() + await release.wait() + if failure_source == "websocket": + raise failure + live.transport.socket.closed = True + + async def close_session(): + live.transport.session.closed = True + if failure_source == "http_session": + raise failure + + live.transport.socket.close.side_effect = close_socket + live.transport.session.close.side_effect = close_session + manager = live.manager(protocol=protocol) + connection = await manager.enter() + first = asyncio.create_task(connection.close()) + second = None + context_exit = None + try: + await asyncio.wait_for(blocked.wait(), timeout=2) + second = asyncio.create_task(connection.close()) + context_exit = asyncio.create_task(live.exit(manager)) + await asyncio.sleep(0) + assert not second.done() + assert not context_exit.done() + release.set() + results = await asyncio.wait_for(asyncio.gather(first, second, context_exit, return_exceptions=True), timeout=2) + assert all(result is failure for result in results) + await connection.close() + await live.exit(manager) + finally: + release.set() + await asyncio.wait_for( + asyncio.gather( + *(task for task in (first, second, context_exit) if task is not None), return_exceptions=True + ), + timeout=2, + ) + live.transport.socket.close.assert_awaited_once() + live.transport.session.close.assert_awaited_once() + assert live.transport.session.closed is True + + +@pytest.mark.parametrize("is_async", [False], ids=["sync"]) +async def test_sync_close_error_propagates_and_does_not_repeat_transport_cleanup(live): + failure = OSError("fake socket close failed") + live.transport.socket.close.side_effect = failure + manager = live.manager() + connection = manager.enter() + with pytest.raises(OSError) as caught: + connection.close() + assert caught.value is failure + assert connection.closed is True + connection.close() + await live.exit(manager) + live.transport.socket.close.assert_called_once_with(code=1000, reason="") + + +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +@pytest.mark.parametrize("code", [1000, 1001]) +async def test_graceful_websocket_closure_ends_iteration_for_both_protocols(live, protocol, code): + if live.is_async: + live.transport.socket.closed = True + live.transport.socket.close_code = code + live.transport.socket.receive.side_effect = [ + _message(aiohttp.WSMsgType.TEXT, json.dumps(_STARTED if protocol == "live" else {"type": "future.event"})), + _message(aiohttp.WSMsgType.CLOSE), + ] + else: + live.transport.socket.recv.side_effect = [ + json.dumps(_STARTED if protocol == "live" else {"type": "future.event"}), + ConnectionClosedOK(Close(code, "finished"), None), + ] + async with live.open(protocol=protocol) as connection: + events = await live.collect(connection) + assert len(events) == 1 + assert events[0].type == "session.started" if protocol == "live" else events[0] == {"type": "future.event"} + assert connection.closed is True + if live.is_async: + live.transport.session.close.assert_awaited_once() + + +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +@pytest.mark.parametrize("code", [1006, 1011]) +async def test_abnormal_websocket_closure_is_not_silently_end_of_stream(live, protocol, code): + if live.is_async: + live.transport.socket.closed = True + live.transport.socket.close_code = code + live.transport.socket.receive.return_value = _message(aiohttp.WSMsgType.CLOSE) + else: + live.transport.socket.recv.side_effect = ConnectionClosedError(Close(code, "failed"), None) + async with live.open(protocol=protocol) as connection: + with pytest.raises(ConnectionResetError) as caught: + await live.collect(connection) + assert caught.value.__cause__ is not None + assert protocol in str(caught.value).lower() + if protocol == "live": + assert "realtime" not in str(caught.value).lower() + assert connection.closed is True + if live.is_async: + live.transport.session.close.assert_awaited_once() + + +@pytest.mark.parametrize("is_async", [False], ids=["sync"]) +async def test_sync_receive_timeout_is_forwarded_and_does_not_close_connection(live): + live.transport.socket.recv.side_effect = [TimeoutError("not ready"), json.dumps(_STARTED)] + async with live.open() as connection: + with pytest.raises(TimeoutError, match="not ready"): + connection.recv(timeout=0.25) + assert connection.closed is False + assert isinstance(connection.recv(timeout=1), models.LiveServerEventLiveSessionStarted) + assert [call.kwargs for call in live.transport.socket.recv.call_args_list] == [ + {"timeout": 0.25}, + {"timeout": 1}, + ] + + +async def test_write_error_propagates_and_context_still_releases_resources(live): + failure = OSError("fake socket write failed") + live.transport.writes.side_effect = failure + with pytest.raises(OSError) as caught: + async with live.open() as connection: + await live.call(connection.response.create) + assert caught.value is failure + live.transport.assert_closed_once() + + +async def test_live_and_realtime_routes_events_and_resources_stay_independent(live): + first = live.transport + second = _Transport(live.is_async) + live.connect.side_effect = [first.socket, second.socket] + live.session_factory.side_effect = [first.session, second.session] + first.queue(_STARTED) + second.queue({"type": "session.created", "session": {}}) + first_manager = live.manager() + second_manager = live.manager(protocol="realtime") + first_connection = await live.call(first_manager.enter) + try: + second_connection = await live.call(second_manager.enter) + try: + assert isinstance(await live.call(first_connection.recv), models.LiveServerEventLiveSessionStarted) + assert isinstance(await live.call(second_connection.recv), models.RealtimeServerEventSessionCreated) + await live.call(first_connection.session.input_audio.mute) + await live.call(second_connection.input_audio_buffer.commit) + await live.call(second_connection.response.cancel, response_id="response-test") + assert first.sent == [{"type": "session.input_audio.mute"}] + assert second.sent == [ + {"type": "input_audio_buffer.commit"}, + {"type": "response.cancel", "response_id": "response-test"}, + ] + await live.call(first_connection.close) + assert first_connection.closed is True + assert second_connection.closed is False + assert not hasattr(first_connection, "input_audio_buffer") + assert not hasattr(first_connection.response, "cancel") + finally: + await live.exit(second_manager) + finally: + await live.exit(first_manager) + first.assert_closed_once() + second.assert_closed_once() + calls = ( + [first.session.ws_connect.await_args, second.session.ws_connect.await_args] + if live.is_async + else live.connect.call_args_list + ) + assert urlsplit(calls[0].args[0]).path.endswith("/endpoint/protocols/voice/live/sessions") + assert urlsplit(calls[1].args[0]).path.endswith("/endpoint/protocols/voice") + option = "protocols" if live.is_async else "subprotocols" + assert not calls[0].kwargs.get(option) + assert list(calls[1].kwargs[option]) == ["realtime"] + + +async def test_sending_while_receiving_does_not_serialize_or_poison_the_other_direction(live): + if live.is_async: + receiving = asyncio.Event() + release = asyncio.Event() + + async def receive(): + receiving.set() + await release.wait() + return _message(aiohttp.WSMsgType.TEXT, json.dumps(_STARTED)) + + live.transport.socket.receive.side_effect = receive + async with live.open() as connection: + task = asyncio.create_task(connection.recv()) + try: + await asyncio.wait_for(receiving.wait(), timeout=2) + await asyncio.wait_for(connection.session.input_audio.append(audio=b"\x00\x01"), timeout=2) + assert not task.done() + assert live.transport.sent == [{"type": "session.input_audio.append", "audio": "AAE="}] + finally: + release.set() + result = await asyncio.wait_for(task, timeout=2) + assert isinstance(result, models.LiveServerEventLiveSessionStarted) + else: + receiving = threading.Event() + release = threading.Event() + + def receive(**kwargs): + receiving.set() + assert release.wait(timeout=5), "The test did not release the fake receiver" + return json.dumps(_STARTED) + + live.transport.socket.recv.side_effect = receive + async with live.open() as connection: + with ThreadPoolExecutor(max_workers=2) as executor: + task = executor.submit(connection.recv) + try: + assert receiving.wait(timeout=2) + sender = executor.submit(connection.session.input_audio.append, audio=b"\x00\x01") + sender.result(timeout=2) + assert not task.done() + assert live.transport.sent == [{"type": "session.input_audio.append", "audio": "AAE="}] + finally: + release.set() + assert isinstance(task.result(timeout=2), models.LiveServerEventLiveSessionStarted) + live.transport.assert_closed_once() + + +async def test_logging_contains_metadata_but_never_tokens_queries_audio_or_text(live, caplog): + synthetic_audio = base64.b64encode(b"synthetic-private-audio").decode("ascii") + live.transport.queue({"type": "session.output_audio.delta", "delta": synthetic_audio}) + caplog.set_level(logging.DEBUG, logger="azure.ai.projects.live") + async with live.open( + connection_url=f"wss://{_HOST}/custom?sig=private-query", + structured_inputs={"name": "private-structured-input"}, + ) as connection: + await live.call(connection.session.input_audio.append, audio=synthetic_audio) + await live.call(connection.session.thinking.append, content="private-outbound-context", delegation_id=None) + await live.call(connection.recv) + messages = "\n".join(record.getMessage() for record in caplog.records if record.name == "azure.ai.projects.live") + assert f"WebSocket CONNECT target=wss://{_HOST}/custom" in messages + assert f"WebSocket CONNECTED target=wss://{_HOST}/custom" in messages + assert "WebSocket SEND type=session.input_audio.append bytes=" in messages + assert "WebSocket RECEIVE type=session.output_audio.delta bytes=" in messages + assert "WebSocket CLOSE code=1000" in messages + for value in (_TOKEN, "private-query", "private-structured-input", "private-outbound-context", synthetic_audio): + assert value not in messages + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +async def test_async_receive_ignores_ping_and_pong_frames(live): + live.transport.socket.receive.side_effect = [ + _message(aiohttp.WSMsgType.PING, b""), + _message(aiohttp.WSMsgType.PONG, b""), + _message(aiohttp.WSMsgType.TEXT, json.dumps(_STARTED)), + ] + async with live.open() as connection: + event = await connection.recv() + assert isinstance(event, models.LiveServerEventLiveSessionStarted) + assert live.transport.socket.receive.await_count == 3 + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("frame_type", [aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSING, aiohttp.WSMsgType.CLOSED]) +async def test_async_remote_close_releases_session_even_when_socket_already_closed(live, frame_type): + live.transport.socket.closed = True + live.transport.socket.close_code = 1000 + live.transport.socket.receive.return_value = _message(frame_type) + manager = live.manager() + connection = await manager.enter() + try: + with pytest.raises(ConnectionResetError) as caught: + await connection.recv() + assert caught.value.__cause__ is None + assert connection.closed is True + finally: + await live.exit(manager) + await connection.close() + await live.exit(manager) + live.transport.session.close.assert_awaited_once() + assert live.transport.session.closed is True + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_async_error_frame_preserves_transport_failure_and_releases_session(live, protocol): + failure = OSError("fake websocket failed") + live.transport.socket.exception.return_value = failure + live.transport.socket.receive.return_value = _message(aiohttp.WSMsgType.ERROR) + async with live.open(protocol=protocol) as connection: + with pytest.raises(ConnectionResetError) as caught: + await live.collect(connection) + assert caught.value.__cause__ is failure + assert protocol in str(caught.value).lower() + if protocol == "live": + assert "realtime" not in str(caught.value).lower() + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("failure", [OSError("close failed"), asyncio.CancelledError()], ids=["error", "cancellation"]) +async def test_async_socket_close_failure_still_releases_session_once(live, failure): + live.transport.socket.close.side_effect = failure + manager = live.manager() + connection = await manager.enter() + with pytest.raises(type(failure)) as caught: + await connection.close() + assert caught.value is failure + live.transport.session.close.assert_awaited_once() + await connection.close() + await live.exit(manager) + live.transport.session.close.assert_awaited_once() + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_async_concurrent_close_only_releases_each_owned_resource_once(live, protocol): + closing = asyncio.Event() + second_started = asyncio.Event() + release = asyncio.Event() + + async def close_socket(**kwargs): + closing.set() + await release.wait() + live.transport.socket.closed = True + + live.transport.socket.close.side_effect = close_socket + manager = live.manager(protocol=protocol) + connection = await manager.enter() + + async def close_again(): + second_started.set() + await connection.close() + + first = asyncio.create_task(connection.close()) + second = None + try: + await asyncio.wait_for(closing.wait(), timeout=2) + second = asyncio.create_task(close_again()) + await asyncio.wait_for(second_started.wait(), timeout=2) + finally: + release.set() + tasks = [first] if second is None else [first, second] + await asyncio.wait_for(asyncio.gather(*tasks), timeout=2) + await live.exit(manager) + live.transport.assert_closed_once() + assert connection.closed is True + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_async_cancellation_during_authentication_cannot_leak_session(live, protocol): + authenticating = asyncio.Event() + block = asyncio.Event() + + async def get_token(*scopes, **kwargs): + live.credential.calls.append((scopes, kwargs)) + authenticating.set() + await block.wait() + return AccessToken(_TOKEN, 9_999_999_999) + + live.credential.get_token = get_token + manager = live.manager(protocol=protocol) + task = asyncio.create_task(manager.enter()) + try: + await asyncio.wait_for(authenticating.wait(), timeout=2) + finally: + task.cancel() + with pytest.raises(asyncio.CancelledError): + await task + assert live.credential.calls == [(_SCOPES, {})] + live.transport.session.ws_connect.assert_not_awaited() + live.transport.socket.close.assert_not_awaited() + assert live.session_factory.call_count <= 1 + assert live.transport.session.close.await_count == live.session_factory.call_count + await live.exit(manager) + assert live.transport.session.close.await_count == live.session_factory.call_count + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_async_cancelled_handshake_releases_session_and_propagates_cancellation(live, protocol): + entering = asyncio.Event() + block = asyncio.Event() + + async def ws_connect(*args, **kwargs): + entering.set() + await block.wait() + return live.transport.socket + + live.transport.session.ws_connect.side_effect = ws_connect + manager = live.manager(protocol=protocol) + task = asyncio.create_task(manager.enter()) + try: + await asyncio.wait_for(entering.wait(), timeout=2) + finally: + task.cancel() + with pytest.raises(asyncio.CancelledError): + await task + live.transport.session.close.assert_awaited_once() + live.transport.socket.close.assert_not_awaited() + await live.exit(manager) + await live.exit(manager) + live.transport.session.close.assert_awaited_once() + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_async_competing_receive_failure_does_not_poison_active_receiver(live, protocol): + receiving = asyncio.Event() + release = asyncio.Event() + active = False + payload = _STARTED if protocol == "live" else {"type": "session.created", "session": {}} + + async def receive(): + nonlocal active + if active: + raise RuntimeError("Concurrent call to receive() is not allowed") + active = True + receiving.set() + try: + await release.wait() + finally: + active = False + return _message(aiohttp.WSMsgType.TEXT, json.dumps(payload)) + + live.transport.socket.receive.side_effect = receive + async with live.open(protocol=protocol) as connection: + task = asyncio.create_task(connection.recv()) + try: + await asyncio.wait_for(receiving.wait(), timeout=2) + with pytest.raises(RuntimeError, match="Concurrent call to receive"): + await connection.recv() + assert not task.done() + assert connection.closed is False + live.transport.socket.close.assert_not_awaited() + live.transport.session.close.assert_not_awaited() + finally: + release.set() + event = await asyncio.wait_for(task, timeout=2) + assert event.type == payload["type"] + live.transport.assert_closed_once() + + +@pytest.mark.parametrize("is_async", [True], ids=["async"]) +@pytest.mark.parametrize("protocol", ["live", "realtime"]) +async def test_async_recv_cancellation_does_not_close_socket_or_cancel_unrelated_work(live, protocol): + receiving = asyncio.Event() + block = asyncio.Event() + calls = 0 + payload = _STARTED if protocol == "live" else {"type": "session.created", "session": {}} + + async def receive(): + nonlocal calls + calls += 1 + if calls == 1: + receiving.set() + try: + await block.wait() + except asyncio.CancelledError: + # aiohttp records 1006 on a cancelled receive without closing the socket. + live.transport.socket.close_code = 1006 + raise + return _message(aiohttp.WSMsgType.TEXT, json.dumps(payload)) + + live.transport.socket.receive.side_effect = receive + async with live.open(protocol=protocol) as connection: + task = asyncio.create_task(connection.recv()) + try: + await asyncio.wait_for(receiving.wait(), timeout=2) + unrelated = asyncio.create_task(connection.send({"type": "future.client.command", "event_id": "evt-other"})) + finally: + task.cancel() + with pytest.raises(asyncio.CancelledError): + await task + await asyncio.wait_for(unrelated, timeout=2) + assert connection.closed is False + live.transport.socket.close.assert_not_awaited() + live.transport.session.close.assert_not_awaited() + assert live.transport.sent == [{"type": "future.client.command", "event_id": "evt-other"}] + event = await asyncio.wait_for(connection.recv(), timeout=2) + expected_type = ( + models.LiveServerEventLiveSessionStarted if protocol == "live" else models.RealtimeServerEventSessionCreated + ) + assert isinstance(event, expected_type) + assert connection.closed is False + live.transport.assert_closed_once() diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_live_conversation_recording_helpers.py b/sdk/ai/azure-ai-projects/tests/agents/test_live_conversation_recording_helpers.py new file mode 100644 index 000000000000..e36b60caae1e --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_live_conversation_recording_helpers.py @@ -0,0 +1,313 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline guards for the recorded REST tests; no service or cassette is used here.""" + +import datetime +import importlib +import io +import json +from pathlib import Path +import re +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock +import wave + +import pytest +from azure.ai.projects import models +from azure.core.exceptions import ResourceNotFoundError + +import live_conversation_test_base as helpers + + +def _audio(channels=1): + common = { + "conversation_id": "conversation-test", + "format": "wav", + "sample_rate": 24000, + "channels": channels, + "duration_ms": 50, + } + if channels == 1: + return models.VoiceAudioItem(dict(common, item_id="item-test", role="agent", codec="pcm16")) + return models.VoiceRecording(dict(common, channel_layout={"left": "user", "right": "agent"})) + + +def _wav(channels=1, silent=False): + stream = io.BytesIO() + sample = b"\x00\x00" if silent else b"\x00\x08" + frame = sample if channels == 1 else b"\x00\x00" + sample + with wave.open(stream, "wb") as recording: + recording.setparams((channels, 2, 24000, 0, "NONE", "not compressed")) + recording.writeframes(frame * 1200) + return stream.getvalue() + + +def test_playback_fixture_never_creates_an_agent_or_opens_a_websocket(monkeypatch): + monkeypatch.setattr(helpers, "is_live", lambda: False) + create_client = MagicMock(side_effect=AssertionError("Playback attempted live setup")) + monkeypatch.setattr(helpers, "AIProjectClient", create_client) + preparer = helpers.LiveConversationPreparer() + preparer.test_class_instance = SimpleNamespace(get_credential=MagicMock()) + preparer.fixture = helpers.LiveConversationFixture("previous-owned-agent", ("previous-conversation",), version="1") + preparer.endpoint = "https://example.invalid/previous-recording" + + result = preparer.create_resource("unused") + preparer.remove_resource("unused") + + assert result["live_conversation_fixture"] == helpers.playback_fixture() + create_client.assert_not_called() + preparer.test_class_instance.get_credential.assert_not_called() + + +def test_playback_preparer_does_not_require_the_legacy_test_resource_counter(monkeypatch): + monkeypatch.setattr(helpers, "is_live", lambda: False) + case = SimpleNamespace(is_live=False, in_recording=False) + received = [] + + def recorded_body(instance, live_conversation_fixture): + assert instance is case + received.append(live_conversation_fixture) + + helpers.LiveConversationPreparer()(recorded_body)(case) + assert received == [helpers.playback_fixture()] + + +@pytest.mark.parametrize("fail_test", [False, True]) +def test_websocket_setup_and_owned_cleanup_are_outside_recorded_transport_patching(monkeypatch, fail_test): + monkeypatch.setattr(helpers, "is_live", lambda: True) + active = {"recorded": False} + calls = [] + fixture = helpers.LiveConversationFixture( + "owned-agent", ("owned-conversation-1", "owned-conversation-2"), (("owned-item-1",), ("owned-item-2",)), "1" + ) + preparer = helpers.LiveConversationPreparer() + + async def create(*args): + assert not active["recorded"] + calls.append("setup") + return fixture + + async def cleanup(): + assert not active["recorded"] + calls.append("cleanup") + + monkeypatch.setattr(preparer, "_create_fixture", create) + monkeypatch.setattr(preparer, "_cleanup_fixture", cleanup) + + def recorded_body(instance, **kwargs): + active["recorded"] = True + try: + assert kwargs["live_conversation_fixture"] is fixture + calls.append("recorded-rest") + if fail_test: + raise ValueError("recorded test failed") + finally: + active["recorded"] = False + + instance = SimpleNamespace(in_recording=False, is_live=True, test_resources_count=0) + wrapped = preparer(recorded_body) + if fail_test: + with pytest.raises(ValueError, match="recorded test failed"): + wrapped( + instance, foundry_project_endpoint="https://example.invalid", foundry_voice_live_model_name="live-test" + ) + else: + wrapped(instance, foundry_project_endpoint="https://example.invalid", foundry_voice_live_model_name="live-test") + assert calls == ["setup", "recorded-rest", "cleanup"] + + +@pytest.mark.asyncio +@pytest.mark.parametrize("asynchronous", [False, True]) +async def test_failed_recorded_assertions_do_not_append_unexpected_cleanup_requests(monkeypatch, asynchronous): + monkeypatch.syspath_prepend(str(Path(__file__).resolve().parents[1])) + module = importlib.import_module("test_voice_agent_live_conversations" + ("_async" if asynchronous else "")) + monkeypatch.setattr(module, "is_live", lambda: False) + case = getattr(module, "TestVoiceAgentLiveConversations" + ("Async" if asynchronous else "")) + body = getattr(case, "_test_live_conversation_rest_lifecycle" + ("_async" if asynchronous else "")) + client = MagicMock() + client.__enter__.return_value = client + client.__aenter__.return_value = client + client.beta.voice_agents.live_conversations.list.return_value.__iter__.return_value = iter(()) + client.beta.voice_agents.live_conversations.list.return_value.__aiter__.return_value = [] + instance = SimpleNamespace( + create_client=MagicMock(return_value=client), create_async_client=MagicMock(return_value=client) + ) + with pytest.raises(AssertionError): + if asynchronous: + await body(instance, live_conversation_fixture=helpers.playback_fixture()) + else: + body(instance, live_conversation_fixture=helpers.playback_fixture()) + client.beta.voice_agents.live_conversations.delete.assert_not_called() + + +def test_sanitizers_keep_agent_conversation_item_and_cursor_references_consistent(monkeypatch): + sanitize = MagicMock() + monkeypatch.setattr(helpers, "add_general_regex_sanitizer", sanitize) + fixture = helpers.LiveConversationFixture( + "owned-agent", + ("owned.conversation+1", "owned.conversation+2"), + (("owned.item+1", "owned.item+2"), ("owned.item+3",)), + "1", + ) + helpers.add_live_conversation_sanitizers(fixture) + assert sanitize.call_count == 6 + wire = json.dumps( + { + "agent_name": fixture.agent_name, + "conversation_ids": fixture.conversation_ids, + "item_ids": fixture.item_ids, + "after": fixture.conversation_ids[0], + "audio": {"conversation_id": fixture.conversation_ids[0], "item_id": fixture.item_ids[0][0]}, + } + ) + for call in sanitize.call_args_list: + assert call.kwargs["function_scoped"] is True + wire = re.sub(call.kwargs["regex"], call.kwargs["value"], wire) + parsed = json.loads(wire) + expected = helpers.playback_fixture() + assert parsed["agent_name"] == expected.agent_name + assert parsed["conversation_ids"] == list(expected.conversation_ids) + assert parsed["after"] == parsed["audio"]["conversation_id"] == expected.conversation_ids[0] + assert parsed["audio"]["item_id"] == parsed["item_ids"][0][0] == "sanitized-live-item-1-1" + assert "owned" not in wire + + +@pytest.mark.asyncio +async def test_fixture_cleanup_deletes_only_owned_versions_even_if_conversation_delete_fails(): + client = MagicMock() + client.beta.voice_agents.live_conversations.delete = AsyncMock(side_effect=[ValueError("delete failed"), None]) + client.agents.delete_version = AsyncMock() + fixture = helpers.LiveConversationFixture("owned-agent", ("first", "second"), version="7") + with pytest.raises(ValueError, match="delete failed"): + await helpers._delete_fixture(client, fixture) + assert client.beta.voice_agents.live_conversations.delete.await_count == 2 + assert [call.args for call in client.beta.voice_agents.live_conversations.delete.await_args_list] == [ + ("owned-agent", "first"), + ("owned-agent", "second"), + ] + client.agents.delete_version.assert_awaited_once_with(agent_name="owned-agent", agent_version="7") + client.agents.delete.assert_not_called() + + +@pytest.mark.asyncio +async def test_fixture_cleanup_tolerates_a_conversation_already_deleted_by_the_recorded_test(): + client = MagicMock() + client.beta.voice_agents.live_conversations.delete = AsyncMock(side_effect=[ResourceNotFoundError("deleted"), None]) + client.agents.delete_version = AsyncMock() + fixture = helpers.LiveConversationFixture("owned-agent", ("first", "second"), version="1") + await helpers._delete_fixture(client, fixture) + assert client.beta.voice_agents.live_conversations.delete.await_count == 2 + client.agents.delete_version.assert_awaited_once_with(agent_name="owned-agent", agent_version="1") + + +@pytest.mark.asyncio +@pytest.mark.parametrize("setup_fails", [False, True]) +async def test_recording_setup_tracks_owned_ids_and_cleans_partial_websocket_failure(monkeypatch, setup_fails): + credential = MagicMock() + credential.__aenter__.return_value = credential + client = MagicMock() + client.__aenter__.return_value = client + client.agents.create_version = AsyncMock(return_value=SimpleNamespace(version="1")) + client.agents.delete_version = AsyncMock() + client.beta.voice_agents.live_conversations.delete = AsyncMock() + constructor = MagicMock(return_value=client) + monkeypatch.setattr(helpers, "AIProjectClient", constructor) + preparer = helpers.LiveConversationPreparer() + preparer.endpoint = "https://example.invalid/api/projects/test" + preparer.test_class_instance = SimpleNamespace(get_credential=MagicMock(return_value=credential)) + + async def hold_greeting(project_client, name, version, conversation_ids): + assert project_client is client and name == "owned-agent" and version == "1" + conversation_ids.append(f"owned-conversation-{len(conversation_ids) + 1}") + if setup_fails: + raise ConnectionError("WebSocket fixture failed") + + monkeypatch.setattr(helpers, "_hold_greeting", hold_greeting) + ready = AsyncMock(side_effect=[("owned-item-1",), ("owned-item-2",)]) + monkeypatch.setattr(helpers, "_wait_for_recording", ready) + if setup_fails: + with pytest.raises(ConnectionError, match="WebSocket fixture failed"): + await preparer._create_fixture("owned-agent", "live-model-test") + client.beta.voice_agents.live_conversations.delete.assert_awaited_once_with( + "owned-agent", "owned-conversation-1" + ) + ready.assert_not_awaited() + else: + fixture = await preparer._create_fixture("owned-agent", "live-model-test") + assert fixture.conversation_ids == ("owned-conversation-1", "owned-conversation-2") + assert fixture.item_ids == (("owned-item-1",), ("owned-item-2",)) + assert fixture.version == "1" + client.agents.delete_version.assert_not_awaited() + preparer.fixture = fixture + await preparer._cleanup_fixture() + assert client.beta.voice_agents.live_conversations.delete.await_count == 2 + client.agents.delete_version.assert_awaited_once_with(agent_name="owned-agent", agent_version="1") + client.agents.delete.assert_not_called() + definition = client.agents.create_version.call_args.kwargs["definition"] + assert definition.store is True and definition.sub_protocol == "live" + assert definition.greeting.text + + +@pytest.mark.parametrize("channels", [1, 2]) +def test_recorded_audio_assertions_parse_pcm_shape_duration_and_agent_channel(channels): + audio = _audio(channels) + helpers.assert_audio_metadata(audio, "conversation-test", item_id="item-test" if channels == 1 else None) + helpers.assert_wav(_wav(channels), audio) + + +@pytest.mark.parametrize("failure", ["silent", "truncated", "wrong-duration", "wrong-format"]) +def test_recorded_audio_assertions_reject_success_shaped_but_invalid_audio(failure): + audio = _audio() + content = _wav(silent=failure == "silent") + if failure == "truncated": + content = content[:-2] + elif failure == "wrong-duration": + audio.duration_ms = datetime.timedelta(seconds=5) + elif failure == "wrong-format": + content = b"not-a-wave-recording" + with pytest.raises(AssertionError): + helpers.assert_wav(content, audio) + + +def test_recorded_audio_requires_actual_managed_content_and_transcript(): + audio = _audio() + assert isinstance(audio, models.VoiceAudioItem) + audio.blob_uri = "https://example.invalid/customer-recording" + with pytest.raises(AssertionError, match="managed content"): + helpers.assert_audio_metadata(audio, "conversation-test", item_id="item-test") + audio.blob_uri = None + item = models.VoiceAgentLiveOutputConversationItem(id="item-test", transcription=" ", audio=audio) + with pytest.raises(AssertionError): + helpers.assert_speech_item(item) + item.transcription = "A synthetic recorded greeting." + helpers.assert_speech_item(item, "item-test") + + +@pytest.mark.parametrize("status", ["in_progress", "failed"]) +def test_recorded_conversation_must_be_durably_completed(status): + conversation = models.VoiceAgentLiveConversation( + {"id": "conversation-test", "status": status, "created_at": 1, "completed_at": 2} + ) + with pytest.raises(AssertionError): + helpers.assert_completed_conversation(conversation, "conversation-test") + + +@pytest.mark.parametrize("invalid", ["route", "status", "header"]) +def test_recorded_http_assertions_reject_old_routes_wrong_status_or_missing_preview(invalid): + response = SimpleNamespace( + http_response=SimpleNamespace(status_code=200), + http_request=SimpleNamespace( + url="https://example.invalid/agents/agent-test/endpoint/protocols/voice/live/conversations", + headers={"Foundry-Features": "VoiceAgents=V1Preview"}, + ), + ) + if invalid == "route": + response.http_request.url = response.http_request.url.replace("/live/", "/") + elif invalid == "status": + response.http_response.status_code = 204 + else: + response.http_request.headers["Foundry-Features"] = "wrong-feature" + with pytest.raises(AssertionError): + helpers.assert_live_status(200)(response) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py b/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py index 2fe8c3214150..62b0ef3001a4 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py @@ -15,6 +15,9 @@ import json import inspect import logging +from contextlib import contextmanager +from copy import deepcopy +from typing import Any, Mapping, get_args, get_type_hints from unittest.mock import MagicMock, patch from urllib.parse import parse_qs, urlparse @@ -22,6 +25,7 @@ from azure.core.credentials import AccessToken from websockets.typing import Subprotocol +from azure.ai.projects import models from azure.ai.projects._realtime import ( BetaRealtime, BetaRealtimeConnectionManager, @@ -34,6 +38,7 @@ RealtimeClientEventResponseCreate, RealtimeServerEventSessionCreated, ) +from azure.ai.projects.operations import BetaRealtimeConnection, ServerEvent _ENDPOINT = "https://my-account.services.ai.azure.com/api/projects/my-project" @@ -70,6 +75,24 @@ def _make_manager(**overrides) -> BetaRealtimeConnectionManager: return BetaRealtimeConnectionManager(**kwargs) +@contextmanager +def _helper_connection(): + sent = [] + transport = MagicMock() + transport.send.side_effect = lambda payload: sent.append(json.loads(payload)) + with patch("websockets.sync.client.connect", return_value=transport): + with _make_manager() as connection: + yield connection, sent + + +def test_public_server_event_union_covers_generated_events_and_shared_error(): + expected_models = set(models.RealtimeServerEvent.__mapping__.values()) | {models.RealtimeServerEventError} + + assert set(get_args(ServerEvent)) == expected_models | {Mapping[str, Any]} + assert get_type_hints(BetaRealtimeConnection.recv)["return"] == ServerEvent + assert get_args(get_type_hints(BetaRealtimeConnection.__iter__)["return"]) == (ServerEvent,) + + class TestToWsUrl: """Unit tests for the pure ``_to_ws_url`` URL-construction helper.""" @@ -191,17 +214,13 @@ def test_enter_caller_user_agent_overrides_default_case_insensitive(self): assert headers["user-agent"] == "custom-user-agent" def test_enter_source_retains_client_identification_wiring(self): - # Regression guard for the SDK client-identification fix (ported from azure-ai-voicelive - # PR #48848) surviving a future TypeSpec regeneration. `_realtime.py` is a hand-written - # file that is NOT `_patch.py`-named, so it isn't covered by the code generator's own - # "never touch _patch.py" guarantee -- nothing in the TypeSpec emitter is aware this file - # exists. The tests above already fail on a *behavioral* regression (wrong header/query - # value), but they exercise the code through mocks and could, in principle, still pass - # against a rewritten implementation that happens to produce the same observable values by - # a different (less safe) path. This inspects the actual source of `enter()` so a partial - # revert -- one that drops the case-insensitive guard, say, while keeping the header value - # correct for the common case -- is caught directly, independent of the tests above. - source = inspect.getsource(BetaRealtimeConnectionManager.enter) + # SDK identification belongs to the authenticated transport shared by Live and Realtime. + source = "\n".join( + inspect.getsource(cls.__dict__[method]) + for cls in BetaRealtimeConnectionManager.__mro__ + for method in ("enter", "_get_query") + if method in cls.__dict__ + ) assert "_USER_AGENT" in source assert "_has_header_case_insensitive" in source assert "x-ms-client-sdk" in source @@ -252,7 +271,7 @@ def test_enter_sends_structured_inputs_as_query_parameter(self): # Regression test: structured_inputs used to be serialized into a custom # "x-ms-voice-structured-inputs" header, but the generated request builder # (build_beta_voice_agents_realtime_connect_voice_agent_request) defines this as the - # "structured_input" query parameter -- the service never actually read the header. + # "structured_inputs" query parameter -- the service never actually read the header. fake_connection = MagicMock() with patch("websockets.sync.client.connect", return_value=fake_connection) as mock_connect: manager = _make_manager(structured_inputs={"greeting_name": "Alex"}) @@ -261,7 +280,8 @@ def test_enter_sends_structured_inputs_as_query_parameter(self): _args, kwargs = mock_connect.call_args query = parse_qs(urlparse(_args[0]).query) - assert json.loads(query["structured_input"][0]) == {"greeting_name": "Alex"} + assert json.loads(query["structured_inputs"][0]) == {"greeting_name": "Alex"} + assert "structured_input" not in query assert "x-ms-voice-structured-inputs" not in kwargs["additional_headers"] def test_enter_preserves_existing_query_on_connection_url_override(self): @@ -306,6 +326,110 @@ def test_context_manager_closes_connection_on_exit(self): class TestRealtimeConnectionRecv: """Unit tests for ``BetaRealtimeConnection.recv()``: event dispatch and error/timeout handling.""" + @pytest.mark.parametrize( + "event_type,event_model", + list(models.RealtimeServerEvent.__mapping__.items()), + ids=list(models.RealtimeServerEvent.__mapping__), + ) + def test_every_generated_realtime_server_event_is_dispatched(self, event_type, event_model): + payload = { + "type": event_type, + "event_id": "event-dispatch", + "output_index": 0, + "content_index": 0, + "future_field": {"enabled": False, "count": 0}, + } + if event_type == "response.audio_timestamp.delta": + payload["timestamp_type"] = "word" + expected = dict(payload) + transport = MagicMock() + transport.recv.return_value = json.dumps(payload) + with patch("websockets.sync.client.connect", return_value=transport): + with _make_manager() as connection: + event = connection.recv() + + assert type(event) is event_model + assert event.type == event_type + assert event.as_dict() == expected + + def test_recv_dispatches_shared_error_not_registered_on_generated_base(self): + payload = { + "type": "error", + "event_id": "event-error", + "error": { + "type": "invalid_request_error", + "code": "invalid_command", + "message": "offline error", + "event_id": "event-request", + "future_field": False, + }, + "future_field": {"enabled": False, "count": 0}, + } + transport = MagicMock() + transport.recv.return_value = json.dumps(payload) + with patch("websockets.sync.client.connect", return_value=transport): + with _make_manager() as connection: + event = connection.recv() + + assert type(event) is models.RealtimeServerEventError + assert event.error.message == "offline error" + assert event.as_dict() == payload + + @pytest.mark.parametrize( + "event_type,event_model", + [ + ("session.handoff.started", models.VoiceAgentServerEventSessionHandoffStarted), + ("session.handoff.completed", models.VoiceAgentServerEventSessionHandoffCompleted), + ("session.handoff.aborted", models.VoiceAgentServerEventSessionHandoffAborted), + ], + ) + def test_recv_dispatches_handoff_events(self, request, event_type, event_model): + payload = { + "type": event_type, + "event_id": "event-test", + "handoff_id": "handoff-test", + "edge_id": "edge-test", + "from_node_id": "$entrypoint", + "to_node_id": "node-test", + "from_model": "source-model-test", + "to_model": "target-model-test", + "tool_call_id": "call-test", + "node_generation": 0, + } + if event_type == "session.handoff.aborted": + payload["reason"] = "user_interruption" + transport = MagicMock() + transport.recv.return_value = json.dumps(payload) + with patch("websockets.sync.client.connect", return_value=transport): + manager = _make_manager() + connection = manager.enter() + request.addfinalizer(manager.__exit__) + event = connection.recv() + assert isinstance(event, event_model) + assert event.as_dict() == payload + + @pytest.mark.parametrize( + "event_type,fields", + [ + ("input_collection.status", {"channel": "dtmf", "status": "completed", "value": "0012"}), + ("response.system_tool_arguments.delta", {"delta": '{"secret":'}), + ("response.system_tool_arguments.done", {"name": "collect_dtmf", "arguments": '{"secret":false}'}), + ], + ) + def test_recv_dispatches_system_tool_events(self, request, event_type, fields): + payload = {"type": event_type, "event_id": "event-test", "call_id": "call-test", **fields} + if event_type.startswith("response."): + payload.update(response_id="response-test", item_id="item-test", output_index=0) + transport = MagicMock() + transport.recv.return_value = json.dumps(payload) + with patch("websockets.sync.client.connect", return_value=transport): + manager = _make_manager() + connection = manager.enter() + request.addfinalizer(manager.__exit__) + event = connection.recv() + assert isinstance(event, models.RealtimeServerEvent.__mapping__[event_type]) + assert event.as_dict() == payload + def test_recv_dispatches_known_event_type(self, request): fake_connection = MagicMock() with patch("websockets.sync.client.connect", return_value=fake_connection): @@ -318,16 +442,17 @@ def test_recv_dispatches_known_event_type(self, request): assert isinstance(event, RealtimeServerEventSessionCreated) def test_recv_unknown_event_type_returns_dict(self, request): + payload = {"type": "some.new.event", "foo": "bar", "future_field": {"enabled": False, "count": 0}} fake_connection = MagicMock() with patch("websockets.sync.client.connect", return_value=fake_connection): manager = _make_manager() conn = manager.enter() request.addfinalizer(manager.__exit__) - fake_connection.recv.return_value = json.dumps({"type": "some.new.event", "foo": "bar"}) + fake_connection.recv.return_value = json.dumps(payload) event = conn.recv() assert isinstance(event, dict) - assert event["foo"] == "bar" + assert event == payload def test_recv_forwards_timeout_to_underlying_connection(self, request): fake_connection = MagicMock() @@ -454,6 +579,175 @@ def test_send_serializes_mapping(self, request): assert json.loads(sent_raw) == {"type": "response.cancel"} +@pytest.mark.parametrize("event_id", [None, "event-helper"], ids=["default-event-id", "explicit-event-id"]) +class TestRealtimeHelperSerialization: + """Exercise the actual resource helper, SDK encoder, and socket send together.""" + + @pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) + def test_session_update_preserves_sparse_settings(self, typed, event_id): + settings = { + "instructions": "", + "temperature": 0.0, + "parallel_tool_calls": False, + "tools": [], + "output_modalities": ["text"], + } + if typed: + session = models.VoiceAgentSessionUpdateConfig(**settings) + expected_settings = {"type": "realtime", **settings} + else: + settings["future_settings"] = {"enabled": False, "count": 0} + session = settings + expected_settings = deepcopy(settings) + original = deepcopy(session) + kwargs = {"event_id": event_id} if event_id is not None else {} + expected = {"type": "session.update", "session": expected_settings, **kwargs} + + with _helper_connection() as (connection, sent): + assert connection.session.update(session=session, **kwargs) is None + + assert sent == [expected] + assert session == original + + @pytest.mark.parametrize( + "helper,arguments,expected", + [ + pytest.param( + "session.avatar_connect", + {"client_sdp": "v=0\r\ns=offline\r\n"}, + {"type": "session.avatar.connect", "client_sdp": "v=0\r\ns=offline\r\n"}, + id="avatar-connect", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": b"\x00\x01\xfe\xff"}, + {"type": "input_audio_buffer.append", "audio": "AAH+/w=="}, + id="append-bytes", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": bytearray(b"\x00\x01\xfe\xff")}, + {"type": "input_audio_buffer.append", "audio": "AAH+/w=="}, + id="append-bytearray", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": "AAH+/w=="}, + {"type": "input_audio_buffer.append", "audio": "AAH+/w=="}, + id="append-base64", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": b""}, + {"type": "input_audio_buffer.append", "audio": ""}, + id="append-empty-bytes", + ), + pytest.param("input_audio_buffer.commit", {}, {"type": "input_audio_buffer.commit"}, id="commit-input"), + pytest.param("input_audio_buffer.clear", {}, {"type": "input_audio_buffer.clear"}, id="clear-input"), + pytest.param("output_audio_buffer.clear", {}, {"type": "output_audio_buffer.clear"}, id="clear-output"), + pytest.param( + "conversation.item.delete", + {"item_id": "item-test"}, + {"type": "conversation.item.delete", "item_id": "item-test"}, + id="delete-item", + ), + pytest.param( + "conversation.item.retrieve", + {"item_id": "item-test"}, + {"type": "conversation.item.retrieve", "item_id": "item-test"}, + id="retrieve-item", + ), + pytest.param( + "conversation.item.truncate", + {"item_id": "item-test", "content_index": 0, "audio_end_ms": 0}, + {"type": "conversation.item.truncate", "item_id": "item-test", "content_index": 0, "audio_end_ms": 0}, + id="truncate-at-zero", + ), + pytest.param( + "conversation.item.truncate", + {"item_id": "item-test", "content_index": 1, "audio_end_ms": 240}, + {"type": "conversation.item.truncate", "item_id": "item-test", "content_index": 1, "audio_end_ms": 240}, + id="truncate-at-offset", + ), + pytest.param("response.create", {}, {"type": "response.create"}, id="create-default-response"), + pytest.param("response.create", {"response": None}, {"type": "response.create"}, id="create-none-response"), + pytest.param( + "response.create", + {"response": {}}, + {"type": "response.create", "response": {}}, + id="create-empty-response", + ), + pytest.param("response.cancel", {}, {"type": "response.cancel"}, id="cancel-current-response"), + pytest.param( + "response.cancel", + {"response_id": "response-test"}, + {"type": "response.cancel", "response_id": "response-test"}, + id="cancel-specific-response", + ), + ], + ) + def test_resource_helpers_send_exact_wire_payload(self, helper, arguments, expected, event_id): + original = deepcopy(arguments) + kwargs = {"event_id": event_id} if event_id is not None else {} + + with _helper_connection() as (connection, sent): + resource = connection + for name in helper.split("."): + resource = getattr(resource, name) + assert resource(**arguments, **kwargs) is None + + assert sent == [{**expected, **kwargs}] + assert arguments == original + + @pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) + @pytest.mark.parametrize("previous_item_id", [None, "", "previous-test"]) + def test_conversation_item_create_preserves_tool_output(self, typed, previous_item_id, event_id): + item_payload = { + "type": "function_call_output", + "call_id": "canonical-call-test", + "output": '{"available":false,"count":0}', + } + if typed: + item = models.RealtimeConversationItemFunctionCallOutput( + call_id="canonical-call-test", output='{"available":false,"count":0}' + ) + else: + item_payload["future_field"] = {"enabled": False, "count": 0} + item = deepcopy(item_payload) + original = deepcopy(item) + kwargs = {"event_id": event_id} if event_id is not None else {} + if previous_item_id is not None: + kwargs["previous_item_id"] = previous_item_id + + with _helper_connection() as (connection, sent): + assert connection.conversation.item.create(item=item, **kwargs) is None + + assert sent == [{"type": "conversation.item.create", "item": item_payload, **kwargs}] + assert item == original + + @pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) + def test_response_create_preserves_per_response_overrides(self, typed, event_id): + response_payload = { + "instructions": "", + "parallel_tool_calls": False, + "input": [], + "output_modalities": ["text"], + } + if typed: + response = models.VoiceAgentResponseCreateParams(**response_payload) + else: + response_payload["future_settings"] = {"enabled": False, "count": 0} + response = deepcopy(response_payload) + original = deepcopy(response) + kwargs = {"event_id": event_id} if event_id is not None else {} + + with _helper_connection() as (connection, sent): + assert connection.response.create(response=response, **kwargs) is None + + assert sent == [{"type": "response.create", "response": response_payload, **kwargs}] + assert response == original + + def test_realtime_logging_emits_metadata_without_sensitive_content(caplog): fake_connection = MagicMock() fake_connection.recv.return_value = json.dumps({"type": "some.new.event", "text": "secret-inbound-content"}) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client_async.py b/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client_async.py index dc0018fb0232..b79470444772 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client_async.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_realtime_client_async.py @@ -15,13 +15,18 @@ import json import inspect import logging +from contextlib import asynccontextmanager +from copy import deepcopy +from typing import Any, Mapping, get_args, get_type_hints from unittest.mock import AsyncMock, MagicMock, patch from urllib.parse import parse_qs, urlparse import pytest from azure.core.credentials import AccessToken +from azure.ai.projects import models from azure.ai.projects.aio._realtime import AsyncBetaRealtime, AsyncBetaRealtimeConnectionManager, _USER_AGENT +from azure.ai.projects.aio.operations import AsyncBetaRealtimeConnection, ServerEvent from azure.ai.projects._version import VERSION from azure.ai.projects.models import ( RealtimeClientEventResponseCreate, @@ -87,6 +92,25 @@ def _patch_client_session(fake_ws_connection): return patch("aiohttp.ClientSession", return_value=fake_session), fake_session +@asynccontextmanager +async def _helper_connection(): + sent = [] + transport = _make_fake_ws() + transport.send_str = AsyncMock(side_effect=lambda payload: sent.append(json.loads(payload))) + patcher, _ = _patch_client_session(transport) + with patcher: + async with _make_manager() as connection: + yield connection, sent + + +async def test_public_server_event_union_covers_generated_events_and_shared_error(): + expected_models = set(models.RealtimeServerEvent.__mapping__.values()) | {models.RealtimeServerEventError} + + assert set(get_args(ServerEvent)) == expected_models | {Mapping[str, Any]} + assert get_type_hints(AsyncBetaRealtimeConnection.recv)["return"] == ServerEvent + assert get_args(get_type_hints(AsyncBetaRealtimeConnection.__aiter__)["return"]) == (ServerEvent,) + + class TestAsyncRealtimeConnectionManagerEnter: """Unit tests for ``AsyncBetaRealtimeConnectionManager.enter()``: URL/header construction and errors.""" @@ -140,7 +164,7 @@ async def test_enter_sends_structured_inputs_as_query_parameter(self): # Regression test: structured_inputs used to be serialized into a custom # "x-ms-voice-structured-inputs" header, but the generated request builder # (build_beta_voice_agents_realtime_connect_voice_agent_request) defines this as the - # "structured_input" query parameter -- the service never actually read the header. + # "structured_inputs" query parameter -- the service never actually read the header. fake_ws = _make_fake_ws() patcher, fake_session = _patch_client_session(fake_ws) with patcher: @@ -149,7 +173,8 @@ async def test_enter_sends_structured_inputs_as_query_parameter(self): await manager.__aexit__() _args, kwargs = fake_session.ws_connect.call_args - assert json.loads(kwargs["params"]["structured_input"]) == {"greeting_name": "Alex"} + assert json.loads(kwargs["params"]["structured_inputs"]) == {"greeting_name": "Alex"} + assert "structured_input" not in kwargs["params"] assert "x-ms-voice-structured-inputs" not in kwargs["headers"] async def test_enter_caller_user_agent_overrides_default_case_insensitive(self): @@ -170,17 +195,13 @@ async def test_enter_caller_user_agent_overrides_default_case_insensitive(self): assert headers["user-agent"] == "custom-user-agent" async def test_enter_source_retains_client_identification_wiring(self): - # Regression guard for the SDK client-identification fix (ported from azure-ai-voicelive - # PR #48848) surviving a future TypeSpec regeneration. `aio/_realtime.py` is a hand-written - # file that is NOT `_patch.py`-named, so it isn't covered by the code generator's own - # "never touch _patch.py" guarantee -- nothing in the TypeSpec emitter is aware this file - # exists. The tests above already fail on a *behavioral* regression (wrong header/query - # value), but they exercise the code through mocks and could, in principle, still pass - # against a rewritten implementation that happens to produce the same observable values by - # a different (less safe) path. This inspects the actual source of `enter()` so a partial - # revert -- one that drops the case-insensitive guard, say, while keeping the header value - # correct for the common case -- is caught directly, independent of the tests above. - source = inspect.getsource(AsyncBetaRealtimeConnectionManager.enter) + # SDK identification belongs to the authenticated transport shared by Live and Realtime. + source = "\n".join( + inspect.getsource(cls.__dict__[method]) + for cls in AsyncBetaRealtimeConnectionManager.__mro__ + for method in ("enter", "_get_query") + if method in cls.__dict__ + ) assert "_USER_AGENT" in source assert "_has_header_case_insensitive" in source assert "x-ms-client-sdk" in source @@ -239,6 +260,125 @@ async def test_context_manager_closes_connection_on_exit(self): class TestAsyncRealtimeConnectionRecv: """Unit tests for ``AsyncBetaRealtimeConnection.recv()``: event dispatch and non-text frames.""" + @pytest.mark.parametrize( + "event_type,event_model", + list(models.RealtimeServerEvent.__mapping__.items()), + ids=list(models.RealtimeServerEvent.__mapping__), + ) + async def test_every_generated_realtime_server_event_is_dispatched(self, event_type, event_model): + import aiohttp + + payload = { + "type": event_type, + "event_id": "event-dispatch", + "output_index": 0, + "content_index": 0, + "future_field": {"enabled": False, "count": 0}, + } + if event_type == "response.audio_timestamp.delta": + payload["timestamp_type"] = "word" + expected = dict(payload) + transport = _make_fake_ws() + transport.receive = AsyncMock(return_value=_make_fake_msg(aiohttp.WSMsgType.TEXT, json.dumps(payload))) + patcher, _ = _patch_client_session(transport) + with patcher: + async with _make_manager() as connection: + event = await connection.recv() + + assert type(event) is event_model + assert event.type == event_type + assert event.as_dict() == expected + + async def test_recv_dispatches_shared_error_not_registered_on_generated_base(self): + import aiohttp + + payload = { + "type": "error", + "event_id": "event-error", + "error": { + "type": "invalid_request_error", + "code": "invalid_command", + "message": "offline error", + "event_id": "event-request", + "future_field": False, + }, + "future_field": {"enabled": False, "count": 0}, + } + transport = _make_fake_ws() + transport.receive = AsyncMock(return_value=_make_fake_msg(aiohttp.WSMsgType.TEXT, json.dumps(payload))) + patcher, _ = _patch_client_session(transport) + with patcher: + async with _make_manager() as connection: + event = await connection.recv() + + assert type(event) is models.RealtimeServerEventError + assert event.error.message == "offline error" + assert event.as_dict() == payload + + @pytest.mark.parametrize( + "event_type", ["session.handoff.started", "session.handoff.completed", "session.handoff.aborted"] + ) + async def test_recv_dispatches_handoff_events(self, event_type): + import aiohttp + + from azure.ai.projects import models + + payload = { + "type": event_type, + "event_id": "event-test", + "handoff_id": "handoff-test", + "edge_id": "edge-test", + "from_node_id": "$entrypoint", + "to_node_id": "node-test", + "from_model": "source-model-test", + "to_model": "target-model-test", + "tool_call_id": "call-test", + "node_generation": 0, + } + if event_type == "session.handoff.aborted": + payload["reason"] = "user_interruption" + transport = _make_fake_ws() + transport.receive = AsyncMock(return_value=_make_fake_msg(aiohttp.WSMsgType.TEXT, json.dumps(payload))) + patcher, _ = _patch_client_session(transport) + with patcher: + manager = _make_manager() + connection = await manager.enter() + try: + event = await connection.recv() + finally: + await manager.__aexit__() + assert isinstance(event, models.RealtimeServerEvent.__mapping__[event_type]) + assert event.as_dict() == payload + + @pytest.mark.parametrize( + "event_type,fields", + [ + ("input_collection.status", {"channel": "dtmf", "status": "completed", "value": "0012"}), + ("response.system_tool_arguments.delta", {"delta": '{"secret":'}), + ("response.system_tool_arguments.done", {"name": "collect_dtmf", "arguments": '{"secret":false}'}), + ], + ) + async def test_recv_dispatches_system_tool_events(self, event_type, fields): + import aiohttp + + from azure.ai.projects import models + + payload = {"type": event_type, "event_id": "event-test", "call_id": "call-test", **fields} + if event_type.startswith("response."): + payload.update(response_id="response-test", item_id="item-test", output_index=0) + transport = _make_fake_ws() + transport.receive = AsyncMock(return_value=_make_fake_msg(aiohttp.WSMsgType.TEXT, json.dumps(payload))) + patcher, _ = _patch_client_session(transport) + with patcher: + manager = _make_manager() + connection = await manager.enter() + try: + event = await connection.recv() + finally: + await manager.__aexit__() + assert isinstance(event, models.RealtimeServerEvent.__mapping__[event_type]) + assert event.as_dict() == payload + async def test_recv_dispatches_known_event_type(self): import aiohttp @@ -282,10 +422,9 @@ async def test_recv_skips_ping_pong_frames(self): async def test_recv_unknown_event_type_returns_dict(self): import aiohttp + payload = {"type": "some.new.event", "foo": "bar", "future_field": {"enabled": False, "count": 0}} fake_ws = _make_fake_ws() - fake_ws.receive = AsyncMock( - return_value=_make_fake_msg(aiohttp.WSMsgType.TEXT, json.dumps({"type": "some.new.event", "foo": "bar"})) - ) + fake_ws.receive = AsyncMock(return_value=_make_fake_msg(aiohttp.WSMsgType.TEXT, json.dumps(payload))) patcher, _ = _patch_client_session(fake_ws) with patcher: manager = _make_manager() @@ -293,7 +432,7 @@ async def test_recv_unknown_event_type_returns_dict(self): try: event = await conn.recv() assert isinstance(event, dict) - assert event["foo"] == "bar" + assert event == payload finally: await manager.__aexit__() @@ -429,6 +568,175 @@ async def test_send_serializes_mapping(self): await manager.__aexit__() +@pytest.mark.parametrize("event_id", [None, "event-helper"], ids=["default-event-id", "explicit-event-id"]) +class TestAsyncRealtimeHelperSerialization: + """Exercise the actual resource helper, SDK encoder, and socket send together.""" + + @pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) + async def test_session_update_preserves_sparse_settings(self, typed, event_id): + settings = { + "instructions": "", + "temperature": 0.0, + "parallel_tool_calls": False, + "tools": [], + "output_modalities": ["text"], + } + if typed: + session = models.VoiceAgentSessionUpdateConfig(**settings) + expected_settings = {"type": "realtime", **settings} + else: + settings["future_settings"] = {"enabled": False, "count": 0} + session = settings + expected_settings = deepcopy(settings) + original = deepcopy(session) + kwargs = {"event_id": event_id} if event_id is not None else {} + expected = {"type": "session.update", "session": expected_settings, **kwargs} + + async with _helper_connection() as (connection, sent): + assert await connection.session.update(session=session, **kwargs) is None + + assert sent == [expected] + assert session == original + + @pytest.mark.parametrize( + "helper,arguments,expected", + [ + pytest.param( + "session.avatar_connect", + {"client_sdp": "v=0\r\ns=offline\r\n"}, + {"type": "session.avatar.connect", "client_sdp": "v=0\r\ns=offline\r\n"}, + id="avatar-connect", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": b"\x00\x01\xfe\xff"}, + {"type": "input_audio_buffer.append", "audio": "AAH+/w=="}, + id="append-bytes", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": bytearray(b"\x00\x01\xfe\xff")}, + {"type": "input_audio_buffer.append", "audio": "AAH+/w=="}, + id="append-bytearray", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": "AAH+/w=="}, + {"type": "input_audio_buffer.append", "audio": "AAH+/w=="}, + id="append-base64", + ), + pytest.param( + "input_audio_buffer.append", + {"audio": b""}, + {"type": "input_audio_buffer.append", "audio": ""}, + id="append-empty-bytes", + ), + pytest.param("input_audio_buffer.commit", {}, {"type": "input_audio_buffer.commit"}, id="commit-input"), + pytest.param("input_audio_buffer.clear", {}, {"type": "input_audio_buffer.clear"}, id="clear-input"), + pytest.param("output_audio_buffer.clear", {}, {"type": "output_audio_buffer.clear"}, id="clear-output"), + pytest.param( + "conversation.item.delete", + {"item_id": "item-test"}, + {"type": "conversation.item.delete", "item_id": "item-test"}, + id="delete-item", + ), + pytest.param( + "conversation.item.retrieve", + {"item_id": "item-test"}, + {"type": "conversation.item.retrieve", "item_id": "item-test"}, + id="retrieve-item", + ), + pytest.param( + "conversation.item.truncate", + {"item_id": "item-test", "content_index": 0, "audio_end_ms": 0}, + {"type": "conversation.item.truncate", "item_id": "item-test", "content_index": 0, "audio_end_ms": 0}, + id="truncate-at-zero", + ), + pytest.param( + "conversation.item.truncate", + {"item_id": "item-test", "content_index": 1, "audio_end_ms": 240}, + {"type": "conversation.item.truncate", "item_id": "item-test", "content_index": 1, "audio_end_ms": 240}, + id="truncate-at-offset", + ), + pytest.param("response.create", {}, {"type": "response.create"}, id="create-default-response"), + pytest.param("response.create", {"response": None}, {"type": "response.create"}, id="create-none-response"), + pytest.param( + "response.create", + {"response": {}}, + {"type": "response.create", "response": {}}, + id="create-empty-response", + ), + pytest.param("response.cancel", {}, {"type": "response.cancel"}, id="cancel-current-response"), + pytest.param( + "response.cancel", + {"response_id": "response-test"}, + {"type": "response.cancel", "response_id": "response-test"}, + id="cancel-specific-response", + ), + ], + ) + async def test_resource_helpers_send_exact_wire_payload(self, helper, arguments, expected, event_id): + original = deepcopy(arguments) + kwargs = {"event_id": event_id} if event_id is not None else {} + + async with _helper_connection() as (connection, sent): + resource = connection + for name in helper.split("."): + resource = getattr(resource, name) + assert await resource(**arguments, **kwargs) is None + + assert sent == [{**expected, **kwargs}] + assert arguments == original + + @pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) + @pytest.mark.parametrize("previous_item_id", [None, "", "previous-test"]) + async def test_conversation_item_create_preserves_tool_output(self, typed, previous_item_id, event_id): + item_payload = { + "type": "function_call_output", + "call_id": "canonical-call-test", + "output": '{"available":false,"count":0}', + } + if typed: + item = models.RealtimeConversationItemFunctionCallOutput( + call_id="canonical-call-test", output='{"available":false,"count":0}' + ) + else: + item_payload["future_field"] = {"enabled": False, "count": 0} + item = deepcopy(item_payload) + original = deepcopy(item) + kwargs = {"event_id": event_id} if event_id is not None else {} + if previous_item_id is not None: + kwargs["previous_item_id"] = previous_item_id + + async with _helper_connection() as (connection, sent): + assert await connection.conversation.item.create(item=item, **kwargs) is None + + assert sent == [{"type": "conversation.item.create", "item": item_payload, **kwargs}] + assert item == original + + @pytest.mark.parametrize("typed", [False, True], ids=["mapping", "generated-model"]) + async def test_response_create_preserves_per_response_overrides(self, typed, event_id): + response_payload = { + "instructions": "", + "parallel_tool_calls": False, + "input": [], + "output_modalities": ["text"], + } + if typed: + response = models.VoiceAgentResponseCreateParams(**response_payload) + else: + response_payload["future_settings"] = {"enabled": False, "count": 0} + response = deepcopy(response_payload) + original = deepcopy(response) + kwargs = {"event_id": event_id} if event_id is not None else {} + + async with _helper_connection() as (connection, sent): + assert await connection.response.create(response=response, **kwargs) is None + + assert sent == [{"type": "response.create", "response": response_payload, **kwargs}] + assert response == original + + async def test_realtime_logging_emits_metadata_without_sensitive_content(caplog): import aiohttp diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_realtime_interruption_helpers.py b/sdk/ai/azure-ai-projects/tests/agents/test_realtime_interruption_helpers.py new file mode 100644 index 000000000000..ce6ddddcdfbc --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_realtime_interruption_helpers.py @@ -0,0 +1,275 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline protocol, audio, and ownership guards for interrupted-audio recordings.""" + +import base64 +import io +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock +import wave + +import pytest + +from azure.ai.projects import models +from azure.core.exceptions import ResourceNotFoundError +import realtime_interruption_test_base as recording_helpers + + +@pytest.fixture +def helpers(): + return recording_helpers._sample_helpers() + + +def _events(): + return [ + {"type": "session.created", "conversation_id": "conversation-test"}, + {"type": "response.created", "response": {"id": "response-test"}}, + { + "type": "response.audio.delta", + "response_id": "response-test", + "item_id": "item-test", + "delta": base64.b64encode(b"\x00\x08" * 4800).decode(), + }, + {"type": "response.done", "response": {"id": "response-test", "status": "cancelled"}}, + {"type": "conversation.item.truncated", "item_id": "item-test", "audio_end_ms": 0}, + ] + + +def _connection(is_async, events): + connection = MagicMock() + factory = AsyncMock if is_async else MagicMock + connection.recv = factory(side_effect=events) + connection.response.create = factory() + connection.response.cancel = factory() + connection.conversation.item.create = factory() + connection.conversation.item.truncate = factory() + return connection + + +def _metadata(**overrides): + payload = { + "conversation_id": "conversation-test", + "item_id": "item-test", + "role": "agent", + "format": "wav", + "codec": "pcm16", + "sample_rate": 24000, + "channels": 1, + "duration_ms": 50, + } + return models.VoiceGeneratedAudioItem(dict(payload, **overrides)) + + +def _wav(*, silent=False): + output = io.BytesIO() + with wave.open(output, "wb") as recording: + recording.setparams((1, 2, 24000, 0, "NONE", "not compressed")) + recording.writeframes((b"\x00\x00" if silent else b"\x00\x08") * 1200) + return output.getvalue() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("is_async", [False, True]) +@pytest.mark.parametrize("reverse_acknowledgements", [False, True]) +@pytest.mark.parametrize("audio_event_type", ["response.audio.delta", "response.output_audio.delta"]) +async def test_interruption_requires_both_cancel_and_truncation( + helpers, is_async, reverse_acknowledgements, audio_event_type +): + events = _events() + events[2]["type"] = audio_event_type + if reverse_acknowledgements: + events[-2:] = reversed(events[-2:]) + connection = _connection(is_async, events) + turn = helpers["InterruptedTurn"]() + + if is_async: + await helpers["interrupt_reply_async"](connection, turn) + connection.response.cancel.assert_awaited_once_with(response_id="response-test") + connection.conversation.item.truncate.assert_awaited_once_with( + item_id="item-test", content_index=0, audio_end_ms=0 + ) + else: + helpers["interrupt_reply"](connection, turn) + connection.response.cancel.assert_called_once_with(response_id="response-test") + connection.conversation.item.truncate.assert_called_once_with( + item_id="item-test", content_index=0, audio_end_ms=0 + ) + assert turn.cancelled and turn.truncated and turn.interruption_requested + assert turn.received_audio_bytes == 9600 + assert turn.conversation_id == "conversation-test" and turn.item_id == "item-test" + + +@pytest.mark.parametrize( + "event", + [ + {"type": "session.created"}, + {"type": "error", "error": {"code": "invalid_request", "message": "synthetic failure"}}, + {"type": "response.created", "response": {}}, + ], +) +def test_missing_identifiers_and_service_errors_cannot_be_success(helpers, event): + with pytest.raises(RuntimeError): + helpers["InterruptedTurn"]().consume(event) + + +def test_silent_or_unrelated_audio_does_not_trigger_interruption(helpers): + turn = helpers["InterruptedTurn"](response_id="response-test") + turn.consume( + { + "type": "response.audio.delta", + "response_id": "other-response", + "item_id": "other-item", + "delta": base64.b64encode(b"\x00\x08" * 4800).decode(), + } + ) + assert turn.received_audio_bytes == 0 + turn.consume( + { + "type": "response.audio.delta", + "response_id": "response-test", + "item_id": "item-test", + "delta": base64.b64encode(bytes(9600)).decode(), + } + ) + assert not turn.ready_to_interrupt + + +def test_partial_pcm_and_unconfirmed_cancellation_are_errors(helpers): + turn = helpers["InterruptedTurn"](response_id="response-test") + with pytest.raises(ValueError, match="partial PCM16"): + turn.consume( + { + "type": "response.audio.delta", + "response_id": "response-test", + "item_id": "item-test", + "delta": base64.b64encode(b"\x01").decode(), + } + ) + with pytest.raises(RuntimeError, match="cancellation"): + turn.consume({"type": "response.done", "response": {"id": "response-test", "status": "completed"}}) + turn.item_id = "item-test" + turn.interruption_requested = True + with pytest.raises(RuntimeError, match="playback position"): + turn.consume({"type": "conversation.item.truncated", "item_id": "item-test", "audio_end_ms": 1}) + + +@pytest.mark.asyncio +async def test_expired_async_deadline_does_not_create_an_unawaited_receive(helpers, monkeypatch): + function = helpers["interrupt_reply_async"] + monkeypatch.setitem(function.__globals__, "TURN_TIMEOUT", -1) + connection = _connection(True, []) + with pytest.raises(TimeoutError, match="session.created"): + await function(connection, helpers["InterruptedTurn"]()) + connection.recv.assert_not_called() + connection.response.create.assert_not_called() + + +@pytest.mark.parametrize( + "overrides", + [ + {"conversation_id": "wrong-conversation"}, + {"item_id": "wrong-item"}, + {"role": "user"}, + {"sample_rate": 16000}, + {"channels": 2}, + {"duration_ms": 0}, + {"blob_uri": "https://example.invalid/customer-recording"}, + ], +) +def test_generated_audio_metadata_must_match_the_interrupted_item(helpers, overrides): + turn = helpers["InterruptedTurn"]( + conversation_id="conversation-test", item_id="wire-item-test", stored_item_id="item-test" + ) + with pytest.raises(ValueError): + helpers["validate_generated_audio"](_metadata(**overrides), _wav(), turn) + + +def test_generated_audio_requires_actual_non_silent_matching_wav(helpers): + turn = helpers["InterruptedTurn"]( + conversation_id="conversation-test", item_id="wire-item-test", stored_item_id="item-test" + ) + helpers["validate_generated_audio"](_metadata(), _wav(), turn) + with pytest.raises(ValueError, match="not a WAV"): + helpers["validate_generated_audio"](_metadata(), b"not audio", turn) + with pytest.raises(ValueError, match="non-silent"): + helpers["validate_generated_audio"](_metadata(), _wav(silent=True), turn) + with pytest.raises(ValueError, match="does not match"): + helpers["validate_generated_audio"](_metadata(duration_ms=1000), _wav(), turn) + fixture = recording_helpers.RealtimeInterruptionFixture("owned-agent", "conversation-test", "item-test") + recording_helpers.assert_generated_wav(_wav(), _metadata(), fixture) + + +def test_playback_never_creates_resources_or_loads_websocket_setup(monkeypatch): + monkeypatch.setattr(recording_helpers, "is_live", lambda: False) + client = MagicMock(side_effect=AssertionError("Playback attempted a live connection")) + loader = MagicMock(side_effect=AssertionError("Playback loaded a live fixture")) + monkeypatch.setattr(recording_helpers, "AIProjectClient", client) + monkeypatch.setattr(recording_helpers, "_sample_helpers", loader) + preparer = recording_helpers.RealtimeInterruptionPreparer() + preparer.test_class_instance = SimpleNamespace(get_credential=MagicMock()) + + assert preparer.create_resource("unused") == {"interrupted_audio_fixture": recording_helpers.playback_fixture()} + preparer.remove_resource("unused") + + client.assert_not_called() + loader.assert_not_called() + preparer.test_class_instance.get_credential.assert_not_called() + + +@pytest.mark.asyncio +async def test_recording_cleanup_still_deletes_owned_agent_after_conversation_failure(): + client = MagicMock() + client.beta.voice_agents.conversations.delete = AsyncMock(side_effect=RuntimeError("cleanup failed")) + client.agents.delete = AsyncMock() + fixture = recording_helpers.RealtimeInterruptionFixture("owned-agent", "conversation-test", "item-test") + with pytest.raises(RuntimeError, match="cleanup failed"): + await recording_helpers._delete_fixture(client, fixture) + client.agents.delete.assert_awaited_once_with(agent_name="owned-agent") + + +@pytest.mark.asyncio +async def test_failed_recording_creation_does_not_delete_an_unacknowledged_name(monkeypatch): + credential = MagicMock() + credential.__aenter__ = AsyncMock(return_value=credential) + credential.__aexit__ = AsyncMock(return_value=False) + client = MagicMock() + client.__aenter__ = AsyncMock(return_value=client) + client.__aexit__ = AsyncMock(return_value=False) + client.agents.create_version = AsyncMock(side_effect=RuntimeError("create failed")) + client.agents.delete = AsyncMock(side_effect=ResourceNotFoundError("not materialized")) + monkeypatch.setattr(recording_helpers, "AIProjectClient", MagicMock(return_value=client)) + preparer = recording_helpers.RealtimeInterruptionPreparer() + preparer.endpoint = "https://example.invalid/api/projects/test" + preparer.test_class_instance = SimpleNamespace(get_credential=MagicMock(return_value=credential)) + + with pytest.raises(RuntimeError, match="create failed"): + await preparer._create_fixture("owned-agent", "realtime-deployment-test") + + client.agents.delete.assert_not_called() + client.beta.voice_agents.conversations.delete.assert_not_called() + + +def test_interruption_sanitizers_preserve_cross_request_references(monkeypatch): + recorded = [] + monkeypatch.setattr(recording_helpers, "add_general_regex_sanitizer", lambda **kwargs: recorded.append(kwargs)) + fixture = recording_helpers.RealtimeInterruptionFixture("owned-agent", "conversation-test", "item-test") + recording_helpers.add_interruption_sanitizers(fixture) + assert [entry["value"] for entry in recorded] == [ + "sanitized-interrupted-audio-agent", + "sanitized-interrupted-conversation", + "sanitized-interrupted-item", + ] + + +def test_stored_item_lookup_uses_response_correlation_not_websocket_item_id(helpers): + stored = [ + {"type": "message", "role": "user", "id": "stored-user"}, + {"type": "message", "role": "assistant", "response_id": "other-response", "id": "other-stored-item"}, + {"type": "message", "role": "assistant", "response_id": "response-test", "id": "stored-assistant"}, + ] + assert helpers["_stored_audio_item"](stored, "response-test") == "stored-assistant" + assert helpers["_stored_audio_item"]([], "response-test") is None + with pytest.raises(RuntimeError, match="exactly one"): + helpers["_stored_audio_item"]([stored[-1], stored[-1]], "response-test") diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_telephony_match_conditions.py b/sdk/ai/azure-ai-projects/tests/agents/test_telephony_match_conditions.py index 20afb5266653..76c01500dcc1 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_telephony_match_conditions.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_telephony_match_conditions.py @@ -4,6 +4,12 @@ from azure.core import MatchConditions from azure.ai.projects._utils.utils import prep_if_match, prep_if_none_match +from azure.ai.projects.models import ( + PhoneNumber, + TelephonyTransferTarget, + TelephonyTransferTargets, + UpdateTelephonyBindingRequest, +) from azure.ai.projects.aio.operations._operations import BetaVoiceAgentsTelephonyOperations as AsyncTelephonyOperations from azure.ai.projects.operations._operations import ( BetaVoiceAgentsTelephonyOperations as TelephonyOperations, @@ -64,3 +70,37 @@ def test_telephony_operations_expose_match_condition(operations_type, method_nam assert parameter.annotation is MatchConditions assert parameter.default is inspect.Parameter.empty + + +def test_telephony_transfer_target_phone_number_round_trip(): + targets = TelephonyTransferTargets( + transfer_targets=[ + TelephonyTransferTarget( + name="sales_desk", + description="Transfers to the sales desk for pricing questions.", + destination=PhoneNumber(value="+14255550123"), + ) + ] + ) + payload = targets.as_dict() + + assert payload == { + "transfer_targets": [ + { + "name": "sales_desk", + "description": "Transfers to the sales desk for pricing questions.", + "destination": {"type": "phone_number", "value": "+14255550123"}, + } + ] + } + restored = TelephonyTransferTargets(payload) + destination = restored.transfer_targets[0].destination + assert isinstance(destination, PhoneNumber) + assert destination.type == "phone_number" + assert destination.value == "+14255550123" + + +def test_telephony_binding_update_serializes_label(): + request = UpdateTelephonyBindingRequest(label="Updated test binding") + + assert request.as_dict() == {"label": "Updated test binding"} diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_campaigns_lro.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_campaigns_lro.py new file mode 100644 index 000000000000..9ee661b52b87 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_campaigns_lro.py @@ -0,0 +1,364 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +# cspell:ignore Acancel +"""Deterministic sync/async tests for campaign LRO completion and resumption.""" + +import asyncio +import inspect +import json +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock +from urllib.parse import parse_qs, urlsplit + +import pytest +from azure.core import MatchConditions +from azure.core.exceptions import HttpResponseError +from azure.core.pipeline import PipelineContext, PipelineResponse +from azure.core.polling import AsyncLROPoller, AsyncPollingMethod, PollingMethod +from azure.core.rest import HttpRequest +from azure.core.utils import case_insensitive_dict + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient +from azure.ai.projects.aio.operations import BetaVoiceAgentsCampaignsOperations as AsyncCampaignsOperations +from azure.ai.projects.models import TelephonyCampaign +from azure.ai.projects.operations import BetaVoiceAgentsCampaignsOperations as CampaignsOperations +from azure.ai.projects.operations._patch import _OperationMethodHeaderProxy +from azure.ai.projects._utils.campaign_polling import _configure_campaign_polling + +pytestmark = pytest.mark.asyncio + +_ENDPOINT = "https://example.test/api/projects/project" +_CAMPAIGN_PATH = "/api/projects/project/agents/voice-agent/telephony_campaigns/campaign" +_CAMPAIGN_URL = f"https://example.test{_CAMPAIGN_PATH}?api-version=v1&tag=one&tag=two" +_MONITOR_URL = "https://example.test/monitors/original-operation?api-version=v1" +_OPERATION_ID = "original-operation" +_METHODS = ("begin_create", "begin_cancel", "begin_delete") +_FEATURES = "VoiceAgents=V1Preview" + + +class _CampaignResponse: + def __init__(self, request, status_code, headers, payload): + self.request = request + self.status_code = status_code + self.headers = case_insensitive_dict(headers) + self.content = json.dumps(payload).encode() if payload is not None else b"" + self.reason = "Test response" + + def text(self): + return self.content.decode() + + def json(self): + return json.loads(self.content) + + +class _SyncCampaignResponse(_CampaignResponse): + def read(self): + return self.content + + +class _AsyncCampaignResponse(_CampaignResponse): + async def read(self): + return self.content + + +def _campaign_payload(): + return { + "name": "campaign", + "connection_name": "connection", + "source": {"type": "phone_number", "value": "+15555550100"}, + "status": "completed", + "operation_id": "later-operation", + } + + +def _response(asynchronous, method, url, status_code, payload, headers=None): + request = HttpRequest(method, url, headers={"x-ms-client-request-id": "request-id"}) + response_type = _AsyncCampaignResponse if asynchronous else _SyncCampaignResponse + response = response_type(request, status_code, headers or {}, payload) + return PipelineResponse(request, response, PipelineContext(None)) + + +def _operation( + asynchronous, + method, + *, + states=("in_progress", "succeeded"), + operation_id=_OPERATION_ID, + initial_status=None, + final_status=200, + initial_url=None, +): + operation_type = AsyncCampaignsOperations if asynchronous else CampaignsOperations + operation = operation_type.__new__(operation_type) + operation._client = MagicMock() + operation._config = SimpleNamespace(polling_interval=0, endpoint=_ENDPOINT) + operation._serialize = MagicMock() + operation._serialize.url.side_effect = lambda name, value, data_type, **kwargs: value + operation._deserialize = MagicMock(side_effect=lambda data_type, value: value) + operation._client.format_url.side_effect = lambda url, **kwargs: url.format(**kwargs) + + verb = {"begin_create": "PUT", "begin_cancel": "POST", "begin_delete": "DELETE"}[method] + url = initial_url or _CAMPAIGN_URL + if method == "begin_cancel": + url = url.replace("?", ":cancel?", 1) + headers = {"Operation-Location": _MONITOR_URL, "Retry-After": "0"} + if operation_id is not None: + headers["operation-id"] = operation_id + payload = _campaign_payload() if method == "begin_create" else {"id": _OPERATION_ID, "status": "queued"} + if initial_status in (200, 204): + headers = {} + if initial_status == 204: + payload = None + initial = _response( + asynchronous, + verb, + url, + initial_status or (201 if method == "begin_create" else 202), + payload, + headers, + ) + initial_method = AsyncMock(return_value=initial) if asynchronous else MagicMock(return_value=initial) + setattr(operation, f"_{method.removeprefix('begin_')}_initial", initial_method) + responses = [ + _response( + asynchronous, + "GET", + _MONITOR_URL, + 200, + {"id": _OPERATION_ID, "status": state, "kind": method.removeprefix("begin_")}, + ) + for state in states + ] + if method != "begin_delete": + payload = ( + _campaign_payload() + if final_status == 200 + else {"error": {"code": "campaign_operation_mismatch", "message": "Campaign was replaced."}} + ) + responses.append(_response(asynchronous, "GET", _CAMPAIGN_URL, final_status, payload)) + operation._client.send_request = ( + AsyncMock(side_effect=responses) if asynchronous else MagicMock(side_effect=responses) + ) + if asynchronous: + operation._client._pipeline._transport.sleep = AsyncMock() + return _OperationMethodHeaderProxy(operation, _FEATURES), operation, initial, initial_method + + +async def _begin(operation, method, **kwargs): + arguments = {"agent_name": "voice-agent", "campaign_name": "campaign"} + if method == "begin_create": + arguments["campaign"] = {} + else: + arguments.update(etag='"etag"', match_condition=MatchConditions.IfNotModified) + arguments.update(kwargs) + result = getattr(operation, method)(**arguments) + return await result if inspect.isawaitable(result) else result + + +async def _result(poller): + if isinstance(poller, AsyncLROPoller): + return await asyncio.wait_for(poller.result(), timeout=5) + return poller.result(timeout=5) + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", _METHODS) +async def test_campaign_lro_completion(asynchronous, method): + operation, raw, _, initial_method = _operation(asynchronous, method) + + poller = await _begin(operation, method) + result = await _result(poller) + + calls = raw._client.send_request.call_args_list + assert initial_method.call_args.kwargs["headers"]["Foundry-Features"] == _FEATURES + assert [call.args[0].url for call in calls[:2]] == [_MONITOR_URL, _MONITOR_URL] + assert all(call.args[0].method == "GET" for call in calls) + assert all(call.kwargs["headers"]["Foundry-Features"] == _FEATURES for call in calls) + if method == "begin_delete": + assert result is None + assert len(calls) == 2 + else: + assert isinstance(result, TelephonyCampaign) + assert result.name == "campaign" + assert result.operation_id == "later-operation" + assert len(calls) == 3 + final_url = urlsplit(calls[-1].args[0].url) + assert final_url.path == _CAMPAIGN_PATH + assert parse_qs(final_url.query) == { + "api-version": ["v1"], + "tag": ["one", "two"], + "operation_id": [_OPERATION_ID], + } + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", _METHODS) +@pytest.mark.parametrize("status", ["cancelled", "Cancelled", "canceled", "failed"]) +async def test_campaign_lro_terminal_failure(asynchronous, method, status): + operation, raw, _, _ = _operation(asynchronous, method, states=(status,)) + + poller = await _begin(operation, method) + + with pytest.raises(HttpResponseError): + await _result(poller) + assert poller.polling_method().finished() + assert raw._client.send_request.call_count == 1 + assert poller.status().lower() == ("canceled" if status.lower() == "cancelled" else status) + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", ("begin_create", "begin_cancel")) +async def test_campaign_lro_requires_original_operation_id(asynchronous, method): + operation, raw, _, _ = _operation(asynchronous, method, states=("succeeded",), operation_id=None) + + poller = await _begin(operation, method) + + with pytest.raises(HttpResponseError, match="Operation-Id"): + await _result(poller) + assert raw._client.send_request.call_count == 1 + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", ("begin_create", "begin_cancel")) +@pytest.mark.parametrize("status", [404, 409]) +async def test_campaign_lro_surfaces_final_get_errors(asynchronous, method, status): + operation, raw, _, _ = _operation(asynchronous, method, states=("succeeded",), final_status=status) + + poller = await _begin(operation, method) + + with pytest.raises(HttpResponseError) as error: + await _result(poller) + assert error.value.status_code == status + assert raw._client.send_request.call_count == 2 + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", _METHODS) +async def test_campaign_lro_polling_can_be_disabled(asynchronous, method): + operation, raw, _, _ = _operation(asynchronous, method) + + poller = await _begin(operation, method, polling=False) + + assert poller.polling_method().finished() + raw._client.send_request.assert_not_called() + assert poller.polling_method().__class__.__name__ == ("AsyncNoPolling" if asynchronous else "NoPolling") + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", _METHODS) +async def test_campaign_lro_preserves_custom_polling(asynchronous, method): + operation, raw, _, _ = _operation(asynchronous, method) + polling = MagicMock(spec=AsyncPollingMethod if asynchronous else PollingMethod) + polling.finished.return_value = True + polling.resource = MagicMock(return_value="custom-result") + + poller = await _begin(operation, method, polling=polling) + + assert poller.polling_method() is polling + assert await _result(poller) == "custom-result" + raw._client.send_request.assert_not_called() + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", _METHODS) +async def test_campaign_lro_preserves_request_options_and_callback(asynchronous, method): + operation, raw, _, initial_method = _operation(asynchronous, method) + callback = MagicMock(return_value="callback-result") + + poller = await _begin( + operation, + method, + cls=callback, + polling_interval=7, + connection_timeout=11, + headers={"X-Test": "custom"}, + ) + + assert await _result(poller) == "callback-result" + assert poller.polling_method()._timeout == 7 + assert initial_method.call_args.kwargs["connection_timeout"] == 11 + assert initial_method.call_args.kwargs["headers"]["X-Test"] == "custom" + for call in raw._client.send_request.call_args_list: + assert call.kwargs["connection_timeout"] == 11 + assert call.kwargs["headers"]["X-Test"] == "custom" + assert call.kwargs["headers"]["Foundry-Features"] == _FEATURES + assert "cls" not in call.kwargs + callback.assert_called_once() + assert ( + callback.call_args.args[1] is None + if method == "begin_delete" + else isinstance(callback.call_args.args[1], TelephonyCampaign) + ) + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method", _METHODS) +async def test_campaign_lro_resumes_original_operation(asynchronous, method): + operation, raw, initial, initial_method = _operation(asynchronous, method) + options = {} + _configure_campaign_polling(options, 0, {"endpoint": _ENDPOINT}, is_async=asynchronous) + polling = options["polling"] + polling.initialize(raw._client, initial, lambda response: None) + token = polling.get_continuation_token() + + poller = await _begin( + operation, + method, + agent_name="different-agent", + campaign_name="different-campaign", + continuation_token=token, + ) + result = await _result(poller) + + initial_method.assert_not_called() + calls = raw._client.send_request.call_args_list + assert calls[0].args[0].url == _MONITOR_URL + if method == "begin_delete": + assert result is None + assert len(calls) == 2 + else: + assert isinstance(result, TelephonyCampaign) + final_url = urlsplit(calls[-1].args[0].url) + assert final_url.path == _CAMPAIGN_PATH + assert parse_qs(final_url.query)["operation_id"] == [_OPERATION_ID] + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize("method,status", [("begin_create", 200), ("begin_delete", 204)]) +async def test_campaign_lro_immediate_completion(asynchronous, method, status): + operation, raw, _, _ = _operation(asynchronous, method, initial_status=status) + + poller = await _begin(operation, method) + result = await _result(poller) + + raw._client.send_request.assert_not_called() + assert result is None if method == "begin_delete" else isinstance(result, TelephonyCampaign) + + +@pytest.mark.parametrize("asynchronous", [False, True]) +async def test_campaign_lro_keeps_encoded_names_and_overrides_stale_guard(asynchronous): + url = f"https://example.test{_CAMPAIGN_PATH}%3Acancel?api-version=v1&operation_id=stale" + operation, raw, _, _ = _operation(asynchronous, "begin_cancel", initial_url=url) + + poller = await _begin(operation, "begin_cancel") + await _result(poller) + + final_url = urlsplit(raw._client.send_request.call_args_list[-1].args[0].url) + assert final_url.path == f"{_CAMPAIGN_PATH}%3Acancel" + assert parse_qs(final_url.query)["operation_id"] == [_OPERATION_ID] + + +@pytest.mark.parametrize("asynchronous", [False, True]) +async def test_campaign_operations_are_wired_to_public_clients(asynchronous): + client_type = AsyncAIProjectClient if asynchronous else AIProjectClient + client = client_type(endpoint=_ENDPOINT, credential=MagicMock(), allow_preview=True) + try: + campaigns = client.beta.voice_agents.campaigns._operation + assert isinstance(campaigns, AsyncCampaignsOperations if asynchronous else CampaignsOperations) + finally: + result = client.close() + if inspect.isawaitable(result): + await result diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud.py index 78fed1d9abd8..9768b543c28c 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud.py @@ -5,8 +5,14 @@ # ------------------------------------ # cSpell:disable +import re +from uuid import uuid4 + +import pytest +from azure.core.exceptions import ResourceNotFoundError + from test_base import TestBase, servicePreparer -from devtools_testutils import recorded_by_proxy, RecordedTransport +from devtools_testutils import recorded_by_proxy, RecordedTransport, add_general_regex_sanitizer from azure.ai.projects.models import ( AgentDetails, AgentKind, @@ -61,6 +67,10 @@ def test_voice_agent_crud(self, **kwargs): # Voice-agent operations require the preview opt-in. project_client = self.create_client(operation_group="agents", allow_preview=True, **kwargs) agent_name = "MyVoiceAgentCrudTest" + if self.is_live: + live_name = f"voice-crud-{uuid4().hex}" + add_general_regex_sanitizer(regex=re.escape(live_name), value=agent_name, function_scoped=True) + agent_name = live_name def make_definition(instructions: str) -> VoiceAgentDefinition: return VoiceAgentDefinition( @@ -73,43 +83,49 @@ def make_definition(instructions: str) -> VoiceAgentDefinition: output_modalities=[VoiceOutputModality.AUDIO], ) - # Create the initial voice agent (version 1). - agent_version1: AgentVersionDetails = project_client.agents.create_version( - agent_name=agent_name, - definition=make_definition("You are a helpful voice assistant."), - ) - self._validate_agent_version(agent_version1, expected_name=agent_name) - assert agent_version1.definition.kind == "voice" # type: ignore[attr-defined] - - # Create a new version with updated instructions. - agent_version2: AgentVersionDetails = project_client.agents.create_version( - agent_name=agent_name, - definition=make_definition("You are a helpful voice assistant. Always greet the caller by name."), - ) - self._validate_agent_version(agent_version2, expected_name=agent_name) - - # Get the voice agent. - retrieved_agent: AgentDetails = project_client.agents.get(agent_name=agent_name) - self._validate_agent(retrieved_agent, expected_name=agent_name, expected_latest_version=agent_version2.version) - - # Retrieve a specific version. - retrieved_agent_version: AgentVersionDetails = project_client.agents.get_version( - agent_name=agent_name, agent_version=agent_version1.version - ) - self._validate_agent_version( - retrieved_agent_version, expected_name=agent_name, expected_version=agent_version1.version - ) - - # List all versions. - item_count = 0 - for listed_agent_version in project_client.agents.list_versions(agent_name=agent_name): - item_count += 1 - self._validate_agent_version(listed_agent_version, expected_name=agent_name) - assert item_count >= 2 - - # Delete the voice agent. - result = project_client.agents.delete(agent_name=agent_name) - assert result.deleted + with project_client: + # Create the initial voice agent (version 1). + agent_version1: AgentVersionDetails = project_client.agents.create_version( + agent_name=agent_name, + definition=make_definition("You are a helpful voice assistant."), + ) + try: + self._validate_agent_version(agent_version1, expected_name=agent_name) + assert isinstance(agent_version1.definition, VoiceAgentDefinition) + assert agent_version1.definition.sub_protocol == "realtime" + + # Create a new version with updated instructions. + agent_version2: AgentVersionDetails = project_client.agents.create_version( + agent_name=agent_name, + definition=make_definition("You are a helpful voice assistant. Always greet the caller by name."), + ) + self._validate_agent_version(agent_version2, expected_name=agent_name) + + # Get the voice agent. + retrieved_agent: AgentDetails = project_client.agents.get(agent_name=agent_name) + self._validate_agent( + retrieved_agent, expected_name=agent_name, expected_latest_version=agent_version2.version + ) + + # Retrieve a specific version. + retrieved_agent_version: AgentVersionDetails = project_client.agents.get_version( + agent_name=agent_name, agent_version=agent_version1.version + ) + self._validate_agent_version( + retrieved_agent_version, expected_name=agent_name, expected_version=agent_version1.version + ) + + # List all versions. + item_count = 0 + for listed_agent_version in project_client.agents.list_versions(agent_name=agent_name): + item_count += 1 + self._validate_agent_version(listed_agent_version, expected_name=agent_name) + assert item_count >= 2 + finally: + result = project_client.agents.delete(agent_name=agent_name) + assert result.deleted + with pytest.raises(ResourceNotFoundError): + project_client.agents.get(agent_name=agent_name) # To run only this test: # pytest tests\agents\test_voice_agent_crud.py::TestVoiceAgentCrud::test_voice_agent_disable_enable -s @@ -133,40 +149,43 @@ def test_voice_agent_disable_enable(self, **kwargs): assert model is not None project_client = self.create_client(operation_group="agents", allow_preview=True, **kwargs) agent_name = "VoiceAgentDisableEnableTest" - - # Delete any existing agent from previous test runs (ignore failures) - try: - project_client.agents.delete(agent_name=agent_name) - except Exception: # pylint: disable=broad-except - pass - - agent_version: AgentVersionDetails = project_client.agents.create_version( - agent_name=agent_name, - definition=VoiceAgentDefinition( - model_type="managed", - model=model, - instructions="You are a helpful voice assistant.", - audio=VoiceAgentAudioConfig( - output=VoiceAgentAudioOutputConfig(voice="en-US-AvaNeural", voice_type="azure-standard") + if self.is_live: + live_name = f"voice-crud-{uuid4().hex}" + add_general_regex_sanitizer(regex=re.escape(live_name), value=agent_name, function_scoped=True) + agent_name = live_name + + with project_client: + agent_version: AgentVersionDetails = project_client.agents.create_version( + agent_name=agent_name, + definition=VoiceAgentDefinition( + model_type="managed", + model=model, + instructions="You are a helpful voice assistant.", + audio=VoiceAgentAudioConfig( + output=VoiceAgentAudioOutputConfig(voice="en-US-AvaNeural", voice_type="azure-standard") + ), + output_modalities=[VoiceOutputModality.AUDIO], ), - output_modalities=[VoiceOutputModality.AUDIO], - ), - ) - self._validate_agent_version(agent_version, expected_name=agent_name) - - # Disable the agent. - project_client.agents.disable(agent_name=agent_name) - disabled_agent: AgentDetails = project_client.agents.get(agent_name=agent_name) - assert str(disabled_agent.state) == "AgentState.DISABLED" or disabled_agent.state == "disabled" - - # Enable the agent. - project_client.agents.enable(agent_name=agent_name) - enabled_agent: AgentDetails = project_client.agents.get(agent_name=agent_name) - assert str(enabled_agent.state) == "AgentState.ENABLED" or enabled_agent.state == "enabled" - - # Delete the voice agent. - result = project_client.agents.delete(agent_name=agent_name) - assert result.deleted + ) + try: + self._validate_agent_version(agent_version, expected_name=agent_name) + assert isinstance(agent_version.definition, VoiceAgentDefinition) + assert agent_version.definition.sub_protocol == "realtime" + + # Disable the agent. + project_client.agents.disable(agent_name=agent_name) + disabled_agent: AgentDetails = project_client.agents.get(agent_name=agent_name) + assert str(disabled_agent.state) == "AgentState.DISABLED" or disabled_agent.state == "disabled" + + # Enable the agent. + project_client.agents.enable(agent_name=agent_name) + enabled_agent: AgentDetails = project_client.agents.get(agent_name=agent_name) + assert str(enabled_agent.state) == "AgentState.ENABLED" or enabled_agent.state == "enabled" + finally: + result = project_client.agents.delete(agent_name=agent_name) + assert result.deleted + with pytest.raises(ResourceNotFoundError): + project_client.agents.get(agent_name=agent_name) # To run only this test: # pytest tests\agents\test_voice_agent_crud.py::TestVoiceAgentCrud::test_generate_agent -s diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud_async.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud_async.py index a16585598a71..a98704e41d44 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud_async.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud_async.py @@ -5,9 +5,15 @@ # ------------------------------------ # cSpell:disable +import re +from uuid import uuid4 + +import pytest +from azure.core.exceptions import ResourceNotFoundError + from test_base import TestBase, servicePreparer from devtools_testutils.aio import recorded_by_proxy_async -from devtools_testutils import RecordedTransport +from devtools_testutils import RecordedTransport, add_general_regex_sanitizer from azure.ai.projects.models import ( AgentDetails, AgentKind, @@ -62,6 +68,10 @@ async def test_voice_agent_crud_async(self, **kwargs): # Voice-agent operations require the preview opt-in. project_client = self.create_async_client(operation_group="agents", allow_preview=True, **kwargs) agent_name = "MyVoiceAgentCrudTestAsync" + if self.is_live: + live_name = f"voice-crud-{uuid4().hex}" + add_general_regex_sanitizer(regex=re.escape(live_name), value=agent_name, function_scoped=True) + agent_name = live_name def make_definition(instructions: str) -> VoiceAgentDefinition: return VoiceAgentDefinition( @@ -80,40 +90,43 @@ def make_definition(instructions: str) -> VoiceAgentDefinition: agent_name=agent_name, definition=make_definition("You are a helpful voice assistant."), ) - self._validate_agent_version(agent_version1, expected_name=agent_name) - assert agent_version1.definition.kind == "voice" # type: ignore[attr-defined] - - # Create a new version with updated instructions. - agent_version2: AgentVersionDetails = await project_client.agents.create_version( - agent_name=agent_name, - definition=make_definition("You are a helpful voice assistant. Always greet the caller by name."), - ) - self._validate_agent_version(agent_version2, expected_name=agent_name) - - # Get the voice agent. - retrieved_agent: AgentDetails = await project_client.agents.get(agent_name=agent_name) - self._validate_agent( - retrieved_agent, expected_name=agent_name, expected_latest_version=agent_version2.version - ) - - # Retrieve a specific version. - retrieved_agent_version: AgentVersionDetails = await project_client.agents.get_version( - agent_name=agent_name, agent_version=agent_version1.version - ) - self._validate_agent_version( - retrieved_agent_version, expected_name=agent_name, expected_version=agent_version1.version - ) - - # List all versions. - item_count = 0 - async for listed_agent_version in project_client.agents.list_versions(agent_name=agent_name): - item_count += 1 - self._validate_agent_version(listed_agent_version, expected_name=agent_name) - assert item_count >= 2 - - # Delete the voice agent. - result = await project_client.agents.delete(agent_name=agent_name) - assert result.deleted + try: + self._validate_agent_version(agent_version1, expected_name=agent_name) + assert isinstance(agent_version1.definition, VoiceAgentDefinition) + assert agent_version1.definition.sub_protocol == "realtime" + + # Create a new version with updated instructions. + agent_version2: AgentVersionDetails = await project_client.agents.create_version( + agent_name=agent_name, + definition=make_definition("You are a helpful voice assistant. Always greet the caller by name."), + ) + self._validate_agent_version(agent_version2, expected_name=agent_name) + + # Get the voice agent. + retrieved_agent: AgentDetails = await project_client.agents.get(agent_name=agent_name) + self._validate_agent( + retrieved_agent, expected_name=agent_name, expected_latest_version=agent_version2.version + ) + + # Retrieve a specific version. + retrieved_agent_version: AgentVersionDetails = await project_client.agents.get_version( + agent_name=agent_name, agent_version=agent_version1.version + ) + self._validate_agent_version( + retrieved_agent_version, expected_name=agent_name, expected_version=agent_version1.version + ) + + # List all versions. + item_count = 0 + async for listed_agent_version in project_client.agents.list_versions(agent_name=agent_name): + item_count += 1 + self._validate_agent_version(listed_agent_version, expected_name=agent_name) + assert item_count >= 2 + finally: + result = await project_client.agents.delete(agent_name=agent_name) + assert result.deleted + with pytest.raises(ResourceNotFoundError): + await project_client.agents.get(agent_name=agent_name) # To run only this test: # pytest tests\agents\test_voice_agent_crud_async.py::TestVoiceAgentCrudAsync::test_voice_agent_disable_enable_async -s @@ -137,14 +150,12 @@ async def test_voice_agent_disable_enable_async(self, **kwargs): assert model is not None project_client = self.create_async_client(operation_group="agents", allow_preview=True, **kwargs) agent_name = "VoiceAgentDisableEnableTestAsync" + if self.is_live: + live_name = f"voice-crud-{uuid4().hex}" + add_general_regex_sanitizer(regex=re.escape(live_name), value=agent_name, function_scoped=True) + agent_name = live_name async with project_client: - # Delete any existing agent from previous test runs (ignore failures) - try: - await project_client.agents.delete(agent_name=agent_name) - except Exception: # pylint: disable=broad-except - pass - agent_version: AgentVersionDetails = await project_client.agents.create_version( agent_name=agent_name, definition=VoiceAgentDefinition( @@ -157,21 +168,25 @@ async def test_voice_agent_disable_enable_async(self, **kwargs): output_modalities=[VoiceOutputModality.AUDIO], ), ) - self._validate_agent_version(agent_version, expected_name=agent_name) - - # Disable the agent. - await project_client.agents.disable(agent_name=agent_name) - disabled_agent: AgentDetails = await project_client.agents.get(agent_name=agent_name) - assert str(disabled_agent.state) == "AgentState.DISABLED" or disabled_agent.state == "disabled" - - # Enable the agent. - await project_client.agents.enable(agent_name=agent_name) - enabled_agent: AgentDetails = await project_client.agents.get(agent_name=agent_name) - assert str(enabled_agent.state) == "AgentState.ENABLED" or enabled_agent.state == "enabled" - - # Delete the voice agent. - result = await project_client.agents.delete(agent_name=agent_name) - assert result.deleted + try: + self._validate_agent_version(agent_version, expected_name=agent_name) + assert isinstance(agent_version.definition, VoiceAgentDefinition) + assert agent_version.definition.sub_protocol == "realtime" + + # Disable the agent. + await project_client.agents.disable(agent_name=agent_name) + disabled_agent: AgentDetails = await project_client.agents.get(agent_name=agent_name) + assert str(disabled_agent.state) == "AgentState.DISABLED" or disabled_agent.state == "disabled" + + # Enable the agent. + await project_client.agents.enable(agent_name=agent_name) + enabled_agent: AgentDetails = await project_client.agents.get(agent_name=agent_name) + assert str(enabled_agent.state) == "AgentState.ENABLED" or enabled_agent.state == "enabled" + finally: + result = await project_client.agents.delete(agent_name=agent_name) + assert result.deleted + with pytest.raises(ResourceNotFoundError): + await project_client.agents.get(agent_name=agent_name) # To run only this test: # pytest tests\agents\test_voice_agent_crud_async.py::TestVoiceAgentCrudAsync::test_generate_agent_async -s diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_feature_models.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_feature_models.py new file mode 100644 index 000000000000..a1ba9d887506 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_feature_models.py @@ -0,0 +1,509 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline wire contracts for native handoff, collection, and post-call configuration.""" + +from collections.abc import Mapping +from datetime import timedelta +import json + +import pytest + +from azure.ai.projects import models + +# Reserved fictional number; used only as inert JSON, never to send or receive an SMS. +_SMS_SENDER = "+12025550123" + +_SYSTEM_TOOLS = [ + pytest.param(models.VoiceAgentCollectDtmfSystemTool, "collect_dtmf", id="collect-dtmf"), + pytest.param(models.VoiceAgentCollectSmsSystemTool, "collect_sms", id="collect-sms"), + pytest.param(models.VoiceAgentSendDtmfSystemTool, "send_dtmf", id="send-dtmf"), + pytest.param(models.VoiceAgentSendSmsSystemTool, "send_sms", id="send-sms"), +] + +_DTMF_COMPLETION_MODES = [ + pytest.param( + models.VoiceAgentDtmfFixedLengthCompletionMode, + {"length": 6, "inter_digit_timeout_seconds": 2}, + {"type": "fixed_length", "length": 6, "inter_digit_timeout_seconds": 2}, + id="fixed-length", + ), + pytest.param( + models.VoiceAgentDtmfTerminatorCompletionMode, + {"terminator": models.VoiceAgentDtmfTerminator.NUMBER_SIGN, "inter_digit_timeout_seconds": 2}, + {"type": "terminator", "terminator": "#", "inter_digit_timeout_seconds": 2}, + id="number-sign", + ), + pytest.param( + models.VoiceAgentDtmfTerminatorCompletionMode, + {"terminator": models.VoiceAgentDtmfTerminator.ASTERISK, "inter_digit_timeout_seconds": 2}, + {"type": "terminator", "terminator": "*", "inter_digit_timeout_seconds": 2}, + id="asterisk", + ), + pytest.param( + models.VoiceAgentDtmfInterDigitSilenceCompletionMode, + {"inter_digit_timeout_seconds": 2}, + {"type": "inter_digit_silence", "inter_digit_timeout_seconds": 2}, + id="inter-digit-silence", + ), +] + + +def _inline_graph(): + return models.VoiceAgentInlineSubagentConfig( + subagents=[ + models.InlineVoiceSubagent( + id="$entrypoint", + display_description="Route the caller to a specialist.", + model="gpt-4.1", + instructions="Route support requests to support.", + parallel_tool_calls=False, + handoff_conditions=[ + models.VoiceAgentHandoffCondition( + id="route-support", + target="support", + condition="The caller needs support.", + cancel_on_interruption=False, + delay_ms=timedelta(0), + target_response=models.VoiceAgentHandoffTargetResponse.NONE, + ) + ], + ), + models.InlineVoiceSubagent( + id="support", + display_description="Answer support questions.", + model="gpt-4.1", + instructions="Answer the support question briefly.", + inherit_base_instructions=False, + tools=[], + tool_choice="none", + temperature=0.0, + max_response_output_tokens=128, + voice_adaptation=models.VoiceAgentHandoffVoiceAdaptation(), + parallel_tool_calls=False, + handoff_conditions=[ + models.VoiceAgentHandoffCondition( + id="return-to-entrypoint", + target="$entrypoint", + condition="The support question is resolved.", + cancel_on_interruption=True, + delay_ms=timedelta(milliseconds=1500), + target_response=models.VoiceAgentHandoffTargetResponse.AUTO, + ) + ], + ), + ], + handoff_policy=models.VoiceAgentHandoffPolicy(max_transfers=2, max_attempts=3), + ) + + +def _inline_graph_wire(): + return { + "subagent_type": "inline", + "subagents": [ + { + "id": "$entrypoint", + "source": "inline", + "interface": "voice", + "description": "Route the caller to a specialist.", + "model": "gpt-4.1", + "instructions": "Route support requests to support.", + "parallel_tool_calls": False, + "handoff_conditions": [ + { + "id": "route-support", + "target": "support", + "condition": "The caller needs support.", + "cancel_on_interruption": False, + "delay_ms": 0, + "target_response": "none", + } + ], + }, + { + "id": "support", + "source": "inline", + "interface": "voice", + "description": "Answer support questions.", + "model": "gpt-4.1", + "instructions": "Answer the support question briefly.", + "inherit_base_instructions": False, + "tools": [], + "tool_choice": "none", + "temperature": 0.0, + "max_response_output_tokens": 128, + "voice_adaptation": {"type": "auto"}, + "parallel_tool_calls": False, + "handoff_conditions": [ + { + "id": "return-to-entrypoint", + "target": "$entrypoint", + "condition": "The support question is resolved.", + "cancel_on_interruption": True, + "delay_ms": 1500, + "target_response": "auto", + } + ], + }, + ], + "handoff_policy": {"max_transfers": 2, "max_attempts": 3}, + } + + +def _assert_inline_graph(config): + assert isinstance(config, models.VoiceAgentInlineSubagentConfig) + assert config.subagent_type == "inline" + assert isinstance(config.handoff_policy, models.VoiceAgentHandoffPolicy) + assert config.handoff_policy.max_transfers == 2 + assert config.handoff_policy.max_attempts == 3 + entrypoint, support = config.subagents + assert all(isinstance(node, models.InlineVoiceSubagent) for node in config.subagents) + assert [node.id for node in config.subagents] == ["$entrypoint", "support"] + assert entrypoint.source == support.source == "inline" + assert entrypoint.interface == support.interface == "voice" + assert entrypoint.display_description == "Route the caller to a specialist." + assert support.display_description == "Answer support questions." + assert support.inherit_base_instructions is False + assert entrypoint.parallel_tool_calls is support.parallel_tool_calls is False + assert support.temperature == 0.0 + assert support.tools == [] + assert support.tool_choice == "none" + assert support.max_response_output_tokens == 128 + assert isinstance(support.voice_adaptation, models.VoiceAgentHandoffVoiceAdaptation) + assert support.voice_adaptation.type == "auto" + outgoing, returning = entrypoint.handoff_conditions[0], support.handoff_conditions[0] + assert isinstance(outgoing, models.VoiceAgentHandoffCondition) + assert isinstance(returning, models.VoiceAgentHandoffCondition) + assert outgoing.target == support.id + assert returning.target == entrypoint.id + assert outgoing.cancel_on_interruption is False + assert returning.cancel_on_interruption is True + assert outgoing.delay_ms == timedelta(0) + assert returning.delay_ms == timedelta(milliseconds=1500) + assert outgoing.target_response == "none" + assert returning.target_response == "auto" + + +def test_inline_handoff_graph_writable_json_roundtrip(): + config = _inline_graph() + expected = _inline_graph_wire() + + assert json.loads(json.dumps(config.as_dict(exclude_readonly=True))) == expected + + restored = models.VoiceAgentInlineSubagentConfig(json.loads(json.dumps(expected))) + _assert_inline_graph(restored) + assert restored.as_dict(exclude_readonly=True) == expected + assert "display_description" not in restored.subagents[0].as_dict() + + +@pytest.mark.parametrize( + "kwargs,expected", + [ + pytest.param({}, {}, id="service-defaults-omitted"), + pytest.param({"max_transfers": 1}, {"max_transfers": 1}, id="attempts-default-omitted"), + pytest.param({"max_transfers": 1, "max_attempts": 1}, {"max_transfers": 1, "max_attempts": 1}, id="minimum"), + pytest.param( + {"max_transfers": 100, "max_attempts": 100}, + {"max_transfers": 100, "max_attempts": 100}, + id="maximum", + ), + ], +) +def test_handoff_policy_writable_json_roundtrip(kwargs, expected): + policy = models.VoiceAgentHandoffPolicy(**kwargs) + assert json.loads(json.dumps(policy.as_dict(exclude_readonly=True))) == expected + + restored = models.VoiceAgentHandoffPolicy(json.loads(json.dumps(expected))) + assert restored.max_transfers == expected.get("max_transfers") + assert restored.max_attempts == expected.get("max_attempts") + assert restored.as_dict(exclude_readonly=True) == expected + + +@pytest.mark.parametrize("delay_ms", [0, 1500, 10000]) +def test_handoff_condition_uses_integer_milliseconds_and_preserves_false(delay_ms): + condition = models.VoiceAgentHandoffCondition( + id="route-support", + target="support", + condition="The caller needs support.", + cancel_on_interruption=False, + delay_ms=timedelta(milliseconds=delay_ms), + target_response=models.VoiceAgentHandoffTargetResponse.NONE, + ) + expected = { + "id": "route-support", + "target": "support", + "condition": "The caller needs support.", + "cancel_on_interruption": False, + "delay_ms": delay_ms, + "target_response": "none", + } + writable = json.loads(json.dumps(condition.as_dict(exclude_readonly=True))) + assert writable == expected + assert type(writable["delay_ms"]) is int + assert writable["cancel_on_interruption"] is False + + restored = models.VoiceAgentHandoffCondition(json.loads(json.dumps(expected))) + assert restored.delay_ms == timedelta(milliseconds=delay_ms) + assert restored.cancel_on_interruption is False + assert restored.target == "support" + assert restored.target_response == "none" + assert restored.transfer_message is None + + +@pytest.mark.parametrize("mode_type,mode_kwargs,mode_wire", _DTMF_COMPLETION_MODES) +def test_dtmf_completion_mode_concrete_writable_json_roundtrip(mode_type, mode_kwargs, mode_wire): + mode = mode_type(**mode_kwargs) + assert json.loads(json.dumps(mode.as_dict(exclude_readonly=True))) == mode_wire + + restored = mode_type(json.loads(json.dumps(mode_wire))) + assert restored.type == mode_wire["type"] + assert restored.inter_digit_timeout_seconds == 2 + if mode_wire["type"] == "fixed_length": + assert restored.length == 6 + elif mode_wire["type"] == "terminator": + assert restored.terminator == mode_wire["terminator"] + assert restored.as_dict(exclude_readonly=True) == mode_wire + + +@pytest.mark.parametrize("mode_type,mode_kwargs,mode_wire", _DTMF_COMPLETION_MODES) +@pytest.mark.parametrize("secret", [False, True], ids=["public-value", "private-reference"]) +def test_dtmf_collection_arguments_writable_json_roundtrip(mode_type, mode_kwargs, mode_wire, secret): + kwargs = { + "secret": secret, + "completion_mode": mode_type(**mode_kwargs), + "timeout_seconds": 60, + "first_digit_timeout_seconds": 5, + } + expected = { + "secret": secret, + "completion_mode": mode_wire, + "timeout_seconds": 60, + "first_digit_timeout_seconds": 5, + } + if secret: + kwargs["output_variable_name"] = "verification_code" + expected["output_variable_name"] = "verification_code" + arguments = models.VoiceAgentCollectDtmfStartArguments(**kwargs) + assert json.loads(json.dumps(arguments.as_dict(exclude_readonly=True))) == expected + assert isinstance(arguments.completion_mode, mode_type) + + restored = models.VoiceAgentCollectDtmfStartArguments(json.loads(json.dumps(expected))) + assert restored.secret is secret + assert restored.timeout_seconds == 60 + assert restored.first_digit_timeout_seconds == 5 + assert restored.output_variable_name == ("verification_code" if secret else None) + mode_data = restored.completion_mode + assert isinstance(mode_data, Mapping) + assert mode_data == mode_wire + # This union has no discriminator base; reconstruct its public member explicitly. + completion_mode = mode_type(dict(mode_data)) + assert completion_mode.type == mode_data["type"] == mode_wire["type"] + assert completion_mode.inter_digit_timeout_seconds == 2 + if mode_wire["type"] == "fixed_length": + assert completion_mode.length == 6 + elif mode_wire["type"] == "terminator": + assert completion_mode.terminator == mode_wire["terminator"] + assert completion_mode.as_dict(exclude_readonly=True) == mode_wire + assert restored.as_dict(exclude_readonly=True) == expected + + +@pytest.mark.parametrize("secret", [False, True], ids=["public-value", "private-reference"]) +def test_sms_collection_arguments_writable_json_roundtrip(secret): + kwargs = {"secret": secret, "from_phone_number": _SMS_SENDER, "timeout_seconds": 60} + expected = {"secret": secret, "from_phone_number": "+12025550123", "timeout_seconds": 60} + if secret: + kwargs["output_variable_name"] = "confirmation_message" + expected["output_variable_name"] = "confirmation_message" + arguments = models.VoiceAgentCollectSmsStartArguments(**kwargs) + assert json.loads(json.dumps(arguments.as_dict(exclude_readonly=True))) == expected + + restored = models.VoiceAgentCollectSmsStartArguments(json.loads(json.dumps(expected))) + assert restored.secret is secret + assert restored.from_phone_number == "+12025550123" + assert restored.timeout_seconds == 60 + assert restored.output_variable_name == ("confirmation_message" if secret else None) + assert restored.as_dict(exclude_readonly=True) == expected + + +@pytest.mark.parametrize( + "argument_type,kwargs,expected", + [ + pytest.param( + models.VoiceAgentCollectionStartArguments, + {"secret": False}, + {"secret": False}, + id="generic", + ), + pytest.param( + models.VoiceAgentCollectDtmfStartArguments, + {"secret": False, "completion_mode": models.VoiceAgentDtmfFixedLengthCompletionMode()}, + {"secret": False, "completion_mode": {"type": "fixed_length"}}, + id="dtmf", + ), + pytest.param( + models.VoiceAgentCollectSmsStartArguments, + {"secret": False, "from_phone_number": _SMS_SENDER}, + {"secret": False, "from_phone_number": "+12025550123"}, + id="sms", + ), + ], +) +def test_collection_arguments_keep_false_without_inventing_service_defaults(argument_type, kwargs, expected): + arguments = argument_type(**kwargs) + assert json.loads(json.dumps(arguments.as_dict(exclude_readonly=True))) == expected + + restored = argument_type(json.loads(json.dumps(expected))) + assert restored.secret is False + assert restored.timeout_seconds is None + assert restored.output_variable_name is None + assert restored.as_dict(exclude_readonly=True) == expected + + +@pytest.mark.parametrize("tool_type,tool_name", _SYSTEM_TOOLS) +@pytest.mark.parametrize("timeout_seconds", [1, 300]) +def test_system_tool_discriminators_and_timeout_roundtrip(tool_type, tool_name, timeout_seconds): + tool = tool_type( + description="Offline system-tool configuration.", timeout_seconds=timedelta(seconds=timeout_seconds) + ) + expected = { + "type": "system", + "name": tool_name, + "description": "Offline system-tool configuration.", + "timeout_seconds": timeout_seconds, + } + writable = json.loads(json.dumps(tool.as_dict(exclude_readonly=True))) + assert writable == expected + assert type(writable["timeout_seconds"]) is int + + wire = { + "kind": "voice", + "sub_protocol": "realtime", + "model_type": "managed", + "model": "gpt-4.1", + "tools": [expected], + } + restored = models.VoiceAgentDefinition(json.loads(json.dumps(wire))) + assert len(restored.tools) == 1 + restored_tool = restored.tools[0] + assert isinstance(restored_tool, tool_type) + assert isinstance(restored_tool, models.VoiceAgentSystemTool) + assert restored_tool.type == "system" + assert restored_tool.name == tool_name + assert restored_tool.description == "Offline system-tool configuration." + assert restored_tool.timeout_seconds == timedelta(seconds=timeout_seconds) + assert restored.as_dict(exclude_readonly=True) == wire + + +@pytest.mark.parametrize("include", [None, []], ids=["omitted", "transcript-only"]) +def test_post_call_destinations_writable_json_roundtrip(include): + config = models.VoiceAgentPostCallConfig( + destinations=[ + models.VoiceAgentEventGridPostCallDestination(connection_name="offline-events"), + models.VoiceAgentRoutinePostCallDestination(name="offline-summary"), + ], + include=include, + ) + expected = { + "destinations": [ + {"type": "event_grid", "connection_name": "offline-events"}, + {"type": "routine", "name": "offline-summary"}, + ] + } + if include is not None: + expected["include"] = [] + assert json.loads(json.dumps(config.as_dict(exclude_readonly=True))) == expected + + restored = models.VoiceAgentPostCallConfig(json.loads(json.dumps(expected))) + event_grid, routine = restored.destinations + assert isinstance(event_grid, models.VoiceAgentEventGridPostCallDestination) + assert isinstance(routine, models.VoiceAgentRoutinePostCallDestination) + assert event_grid.type == "event_grid" + assert event_grid.connection_name == "offline-events" + assert routine.type == "routine" + assert routine.name == "offline-summary" + assert restored.include == include + assert restored.as_dict(exclude_readonly=True) == expected + + +def test_native_voice_definition_preserves_advanced_feature_models_on_version_readback(): + definition = models.VoiceAgentDefinition( + model_type=models.VoiceModelType.MANAGED, + model="gpt-4.1", + instructions="Help the caller and route support questions.", + store=False, + parallel_tool_calls=False, + subagent_config=_inline_graph(), + tools=[ + models.VoiceAgentCollectDtmfSystemTool(), + models.VoiceAgentCollectSmsSystemTool(), + models.VoiceAgentSendDtmfSystemTool(), + models.VoiceAgentSendSmsSystemTool(), + ], + post_call=models.VoiceAgentPostCallConfig( + destinations=[ + models.VoiceAgentEventGridPostCallDestination(connection_name="offline-events"), + models.VoiceAgentRoutinePostCallDestination(name="offline-summary"), + ], + include=[], + ), + ) + expected = { + "kind": "voice", + "sub_protocol": "realtime", + "model_type": "managed", + "model": "gpt-4.1", + "instructions": "Help the caller and route support questions.", + "store": False, + "parallel_tool_calls": False, + "subagent_config": _inline_graph_wire(), + "tools": [ + {"type": "system", "name": "collect_dtmf"}, + {"type": "system", "name": "collect_sms"}, + {"type": "system", "name": "send_dtmf"}, + {"type": "system", "name": "send_sms"}, + ], + "post_call": { + "destinations": [ + {"type": "event_grid", "connection_name": "offline-events"}, + {"type": "routine", "name": "offline-summary"}, + ], + "include": [], + }, + } + assert json.loads(json.dumps(definition.as_dict(exclude_readonly=True))) == expected + + wire = { + "object": "agent.version", + "id": "offline-voice:1", + "name": "offline-voice", + "version": "1", + "created_at": 1700000000, + "metadata": {}, + "definition": expected, + } + version = models.AgentVersionDetails(json.loads(json.dumps(wire))) + restored = version.definition + assert isinstance(restored, models.VoiceAgentDefinition) + assert restored.kind == "voice" + assert restored.sub_protocol == "realtime" + assert restored.model_type == "managed" + assert restored.model == "gpt-4.1" + assert restored.store is False + assert restored.parallel_tool_calls is False + _assert_inline_graph(restored.subagent_config) + assert len(restored.tools) == 4 + assert isinstance(restored.tools[0], models.VoiceAgentCollectDtmfSystemTool) + assert isinstance(restored.tools[1], models.VoiceAgentCollectSmsSystemTool) + assert isinstance(restored.tools[2], models.VoiceAgentSendDtmfSystemTool) + assert isinstance(restored.tools[3], models.VoiceAgentSendSmsSystemTool) + assert [tool.name for tool in restored.tools] == ["collect_dtmf", "collect_sms", "send_dtmf", "send_sms"] + assert isinstance(restored.post_call, models.VoiceAgentPostCallConfig) + event_grid, routine = restored.post_call.destinations + assert isinstance(event_grid, models.VoiceAgentEventGridPostCallDestination) + assert isinstance(routine, models.VoiceAgentRoutinePostCallDestination) + assert event_grid.connection_name == "offline-events" + assert routine.name == "offline-summary" + assert restored.post_call.include == [] + assert restored.as_dict(exclude_readonly=True) == expected + assert version.as_dict() == wire diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_generated_audio.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_generated_audio.py new file mode 100644 index 000000000000..e105256f9ef0 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_generated_audio.py @@ -0,0 +1,84 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Recorded generated-audio behavior after cancelling a real response.""" + +import pytest + +from azure.core.exceptions import ResourceNotFoundError +from devtools_testutils import is_live, recorded_by_proxy +from test_base import TestBase +from realtime_interruption_test_base import ( + RealtimeInterruptionPreparer, + add_interruption_sanitizers, + assert_conversation_deleted, + assert_generated_metadata, + assert_generated_status, + assert_generated_wav, + interruptionServicePreparer, +) + + +class TestVoiceAgentGeneratedAudio(TestBase): + @interruptionServicePreparer() + @RealtimeInterruptionPreparer() + @recorded_by_proxy() + def test_interrupted_generated_audio(self, interrupted_audio_fixture, **kwargs): + fixture = interrupted_audio_fixture + if is_live(): + add_interruption_sanitizers(fixture) + with self.create_client(allow_preview=True, **kwargs) as client: + conversations = client.beta.voice_agents.conversations + try: + metadata = conversations.get_generated_audio_item( + fixture.agent_name, + fixture.conversation_id, + fixture.item_id, + raw_response_hook=assert_generated_status((200, 404)), + ) + except ResourceNotFoundError as error: + # Cancellation may stop rendering before a complete generated artifact exists. + assert error.status_code == 404 + assert error.error and error.error.code == "not_found" + assert error.message and "generated audio" in error.message.casefold() + assert fixture.item_id in error.message + with pytest.raises(ResourceNotFoundError) as download_error: + b"".join( + conversations.download_generated_audio_item( + fixture.agent_name, + fixture.conversation_id, + fixture.item_id, + raw_response_hook=assert_generated_status(404), + ) + ) + assert download_error.value.status_code == 404 + else: + assert_generated_metadata(metadata, fixture) + content = b"".join( + conversations.download_generated_audio_item( + fixture.agent_name, + fixture.conversation_id, + fixture.item_id, + raw_response_hook=assert_generated_status(200), + ) + ) + assert_generated_wav(content, metadata, fixture) + conversations.delete( + fixture.agent_name, + fixture.conversation_id, + raw_response_hook=assert_conversation_deleted, + ) + for operation, streamed in ( + (conversations.get_generated_audio_item, False), + (conversations.download_generated_audio_item, True), + ): + with pytest.raises(ResourceNotFoundError): + result = operation( + fixture.agent_name, + fixture.conversation_id, + fixture.item_id, + raw_response_hook=assert_generated_status(404), + ) + if streamed: + list(result) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_conversations.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_conversations.py new file mode 100644 index 000000000000..04be0b260943 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_conversations.py @@ -0,0 +1,118 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Test Proxy recorded coverage of all nine dedicated GPT Live REST operations. + +Recording needs FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_VOICE_LIVE_MODEL_NAME. +The latter is the existing GPT Live deployment name, not a model catalog ID. +The outer fixture preparer creates owned stored sessions outside HTTP recording; +playback performs REST calls only. These cases remain enabled without recordings +so missing Test Proxy assets are visible rather than hidden by a skip marker. +""" + +import pytest + +from azure.ai.projects import models +from azure.core.exceptions import ResourceNotFoundError +from devtools_testutils import is_live, recorded_by_proxy +from test_base import TestBase +from live_conversation_test_base import ( + LiveConversationPreparer, + add_live_conversation_sanitizers, + assert_audio_metadata, + assert_completed_conversation, + assert_live_status, + assert_speech_item, + assert_wav, + liveConversationServicePreparer, +) + + +class TestVoiceAgentLiveConversations(TestBase): + @liveConversationServicePreparer() + @LiveConversationPreparer() + @recorded_by_proxy() + def test_live_conversation_rest_lifecycle(self, live_conversation_fixture, **kwargs): + self._test_live_conversation_rest_lifecycle(live_conversation_fixture, **kwargs) + + def _test_live_conversation_rest_lifecycle(self, live_conversation_fixture, **kwargs): + fixture = live_conversation_fixture + if is_live(): + add_live_conversation_sanitizers(fixture) + with self.create_client(allow_preview=True, **kwargs) as client: + conversations = client.beta.voice_agents.live_conversations + agent_name, conversation_id = fixture.agent_name, fixture.conversation_ids[0] + listed = list( + conversations.list(agent_name, limit=1, order="asc", raw_response_hook=assert_live_status(200)) + ) + assert [value.id for value in listed] == list(fixture.conversation_ids) + for value in listed: + assert_completed_conversation(value, value.id) + detail = conversations.get(agent_name, conversation_id, raw_response_hook=assert_live_status(200)) + assert_completed_conversation(detail, conversation_id) + + items = list( + conversations.list_items( + agent_name, conversation_id, limit=1, order="asc", raw_response_hook=assert_live_status(200) + ) + ) + assert items and len({item.id for item in items}) == len(items) + assert all(isinstance(item, models.VoiceAgentLiveConversationItem) for item in items) + speech = [item for item in items if isinstance(item, models.VoiceAgentLiveOutputConversationItem)] + assert speech, "Stored greeting speech must exercise item audio, not just metadata/list routes" + for item in speech: + assert_speech_item(item) + fetched = conversations.get_item( + agent_name, conversation_id, item.id, raw_response_hook=assert_live_status(200) + ) + fetched = assert_speech_item(fetched, item.id) + assert fetched.transcription == item.transcription + audio = conversations.get_audio_item( + agent_name, conversation_id, item.id, raw_response_hook=assert_live_status(200) + ) + assert_audio_metadata(audio, conversation_id, item_id=item.id) + assert_wav( + b"".join( + conversations.download_audio_item( + agent_name, conversation_id, item.id, raw_response_hook=assert_live_status(200) + ) + ), + audio, + ) + recording = conversations.get_audio(agent_name, conversation_id, raw_response_hook=assert_live_status(200)) + assert_audio_metadata(recording, conversation_id) + assert_wav( + b"".join( + conversations.download_audio(agent_name, conversation_id, raw_response_hook=assert_live_status(200)) + ), + recording, + ) + + conversations.delete(agent_name, conversation_id, raw_response_hook=assert_live_status(204)) + with pytest.raises(ResourceNotFoundError): + conversations.get(agent_name, conversation_id, raw_response_hook=assert_live_status(404)) + with pytest.raises(ResourceNotFoundError): + conversations.get_item( + agent_name, conversation_id, speech[0].id, raw_response_hook=assert_live_status(404) + ) + with pytest.raises(ResourceNotFoundError): + conversations.get_audio(agent_name, conversation_id, raw_response_hook=assert_live_status(404)) + with pytest.raises(ResourceNotFoundError): + conversations.get_audio_item( + agent_name, conversation_id, speech[0].id, raw_response_hook=assert_live_status(404) + ) + with pytest.raises(ResourceNotFoundError): + list( + conversations.download_audio(agent_name, conversation_id, raw_response_hook=assert_live_status(404)) + ) + with pytest.raises(ResourceNotFoundError): + list( + conversations.download_audio_item( + agent_name, conversation_id, speech[0].id, raw_response_hook=assert_live_status(404) + ) + ) + remaining = list( + conversations.list(agent_name, limit=1, order="asc", raw_response_hook=assert_live_status(200)) + ) + assert [value.id for value in remaining] == list(fixture.conversation_ids[1:]) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_conversations_async.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_conversations_async.py new file mode 100644 index 000000000000..1c83a11a01a7 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_conversations_async.py @@ -0,0 +1,113 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Async Test Proxy coverage of the same GPT Live REST lifecycle as the sync test.""" + +import pytest + +from azure.ai.projects import models +from azure.core.exceptions import ResourceNotFoundError +from devtools_testutils import is_live +from devtools_testutils.aio import recorded_by_proxy_async +from test_base import TestBase +from live_conversation_test_base import ( + LiveConversationPreparer, + add_live_conversation_sanitizers, + assert_audio_metadata, + assert_completed_conversation, + assert_live_status, + assert_speech_item, + assert_wav, + liveConversationServicePreparer, +) + + +class TestVoiceAgentLiveConversationsAsync(TestBase): + @liveConversationServicePreparer() + @LiveConversationPreparer() + @recorded_by_proxy_async() + async def test_live_conversation_rest_lifecycle_async(self, live_conversation_fixture, **kwargs): + await self._test_live_conversation_rest_lifecycle_async(live_conversation_fixture, **kwargs) + + async def _test_live_conversation_rest_lifecycle_async(self, live_conversation_fixture, **kwargs): + fixture = live_conversation_fixture + if is_live(): + add_live_conversation_sanitizers(fixture) + async with self.create_async_client(allow_preview=True, **kwargs) as client: + conversations = client.beta.voice_agents.live_conversations + agent_name, conversation_id = fixture.agent_name, fixture.conversation_ids[0] + listed = [ + value + async for value in conversations.list( + agent_name, limit=1, order="asc", raw_response_hook=assert_live_status(200) + ) + ] + assert [value.id for value in listed] == list(fixture.conversation_ids) + for value in listed: + assert_completed_conversation(value, value.id) + detail = await conversations.get(agent_name, conversation_id, raw_response_hook=assert_live_status(200)) + assert_completed_conversation(detail, conversation_id) + + items = [ + item + async for item in conversations.list_items( + agent_name, conversation_id, limit=1, order="asc", raw_response_hook=assert_live_status(200) + ) + ] + assert items and len({item.id for item in items}) == len(items) + assert all(isinstance(item, models.VoiceAgentLiveConversationItem) for item in items) + speech = [item for item in items if isinstance(item, models.VoiceAgentLiveOutputConversationItem)] + assert speech, "Stored greeting speech must exercise item audio, not just metadata/list routes" + for item in speech: + assert_speech_item(item) + fetched = await conversations.get_item( + agent_name, conversation_id, item.id, raw_response_hook=assert_live_status(200) + ) + fetched = assert_speech_item(fetched, item.id) + assert fetched.transcription == item.transcription + audio = await conversations.get_audio_item( + agent_name, conversation_id, item.id, raw_response_hook=assert_live_status(200) + ) + assert_audio_metadata(audio, conversation_id, item_id=item.id) + stream = await conversations.download_audio_item( + agent_name, conversation_id, item.id, raw_response_hook=assert_live_status(200) + ) + assert_wav(b"".join([chunk async for chunk in stream]), audio) + recording = await conversations.get_audio( + agent_name, conversation_id, raw_response_hook=assert_live_status(200) + ) + assert_audio_metadata(recording, conversation_id) + stream = await conversations.download_audio( + agent_name, conversation_id, raw_response_hook=assert_live_status(200) + ) + assert_wav(b"".join([chunk async for chunk in stream]), recording) + + await conversations.delete(agent_name, conversation_id, raw_response_hook=assert_live_status(204)) + with pytest.raises(ResourceNotFoundError): + await conversations.get(agent_name, conversation_id, raw_response_hook=assert_live_status(404)) + with pytest.raises(ResourceNotFoundError): + await conversations.get_item( + agent_name, conversation_id, speech[0].id, raw_response_hook=assert_live_status(404) + ) + with pytest.raises(ResourceNotFoundError): + await conversations.get_audio(agent_name, conversation_id, raw_response_hook=assert_live_status(404)) + with pytest.raises(ResourceNotFoundError): + await conversations.get_audio_item( + agent_name, conversation_id, speech[0].id, raw_response_hook=assert_live_status(404) + ) + with pytest.raises(ResourceNotFoundError): + await conversations.download_audio( + agent_name, conversation_id, raw_response_hook=assert_live_status(404) + ) + with pytest.raises(ResourceNotFoundError): + await conversations.download_audio_item( + agent_name, conversation_id, speech[0].id, raw_response_hook=assert_live_status(404) + ) + remaining = [ + value + async for value in conversations.list( + agent_name, limit=1, order="asc", raw_response_hook=assert_live_status(200) + ) + ] + assert [value.id for value in remaining] == list(fixture.conversation_ids[1:]) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_crud.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_crud.py new file mode 100644 index 000000000000..8b45e2e2d7f3 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_crud.py @@ -0,0 +1,105 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Recorded HTTP-only CRUD for all native persisted Live delegation owners.""" + +from contextlib import ExitStack + +import pytest +from azure.ai.projects import models +from azure.core.exceptions import ResourceNotFoundError +from devtools_testutils import recorded_by_proxy + +from test_base import TestBase +from live_agent_crud_test_base import ( + PROMPT_INSTRUCTIONS, + assert_live_version, + live_definition, + liveAgentServicePreparer, + owned_agent_name, + sanitize_live_deployments, +) + + +class TestVoiceAgentLiveCrud(TestBase): + # Separate nodes avoid parametrized-recorder decorator argument loss. + @liveAgentServicePreparer() + @recorded_by_proxy() + def test_live_agent_client_crud(self, **kwargs): + self._exercise_crud("client", **kwargs) + + @liveAgentServicePreparer() + @recorded_by_proxy() + def test_live_agent_responses_crud(self, **kwargs): + self._exercise_crud("responses", **kwargs) + + @liveAgentServicePreparer() + @recorded_by_proxy() + def test_live_agent_managed_agent_crud(self, **kwargs): + self._exercise_crud("foundry_managed_agent", **kwargs) + + def _exercise_crud(self, mode, **kwargs): + sanitize_live_deployments(kwargs) + name = owned_agent_name(mode, live=self.is_live) + backend_name = owned_agent_name("prompt", live=self.is_live) if mode == "foundry_managed_agent" else None + with self.create_client(allow_preview=True, **kwargs) as client: + + def delete_owned_version(agent_name, agent_version): + result = client.agents.delete_version(agent_name=agent_name, agent_version=agent_version) + assert isinstance(result, models.DeleteAgentVersionResponse) + assert result.name == agent_name and result.version == agent_version + assert result.deleted + with pytest.raises(ResourceNotFoundError): + client.agents.get_version(agent_name=agent_name, agent_version=agent_version) + + with ExitStack() as cleanup: + backend = None + if backend_name is not None: + backend = client.agents.create_version( + agent_name=backend_name, + definition=models.PromptAgentDefinition( + model=kwargs["foundry_model_name"], instructions=PROMPT_INSTRUCTIONS + ), + ) + cleanup.callback(delete_owned_version, backend_name, backend.version) + self._validate_agent_version(backend, expected_name=backend_name) + retrieved_backend = client.agents.get_version( + agent_name=backend_name, agent_version=backend.version + ) + self._validate_agent_version( + retrieved_backend, expected_name=backend_name, expected_version=backend.version + ) + assert isinstance(retrieved_backend.definition, models.PromptAgentDefinition) + assert retrieved_backend.definition.model == kwargs["foundry_model_name"] + assert retrieved_backend.definition.instructions == PROMPT_INSTRUCTIONS + + versions = {} + for instructions in ("Delegate the spoken question.", "Delegate the spoken question; answer briefly."): + definition = live_definition( + mode, + kwargs["foundry_voice_live_model_name"], + kwargs["foundry_model_name"], + instructions, + backend=backend, + ) + created = client.agents.create_version(agent_name=name, definition=definition) + cleanup.callback(delete_owned_version, name, created.version) + assert_live_version(created, definition, name=name) + assert created.version not in versions + versions[created.version] = definition + + latest_version = created.version + agent = client.agents.get(agent_name=name) + self._validate_agent(agent, expected_name=name, expected_latest_version=latest_version) + assert_live_version( + agent.versions.latest, versions[latest_version], name=name, version_id=latest_version + ) + for version_id, expected in versions.items(): + retrieved = client.agents.get_version(agent_name=name, agent_version=version_id) + assert_live_version(retrieved, expected, name=name, version_id=version_id) + + listed = {version.version: version for version in client.agents.list_versions(agent_name=name)} + assert set(listed) == set(versions) + for version_id, expected in versions.items(): + assert_live_version(listed[version_id], expected, name=name, version_id=version_id) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_models.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_models.py new file mode 100644 index 000000000000..001051e6996f --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_live_models.py @@ -0,0 +1,147 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline coverage for persisted Live definitions, not session-update DTOs.""" + +import json + +import pytest + +from azure.ai.projects import models + +_DELEGATIONS = [ + pytest.param( + models.VoiceAgentLiveClientDelegation, + {"acknowledgement_delay_ms": 0}, + {"type": "client", "acknowledgement_delay_ms": 0}, + id="client", + ), + pytest.param( + models.VoiceAgentLiveResponsesDelegation, + { + "acknowledgement_delay_ms": 0, + "responses": models.LiveResponsesDelegationSettingsInputParam( + model="backend-deployment-test", instructions="Answer briefly." + ), + }, + { + "type": "responses", + "acknowledgement_delay_ms": 0, + "responses": {"model": "backend-deployment-test", "instructions": "Answer briefly."}, + }, + id="responses", + ), + pytest.param( + models.VoiceAgentLiveManagedAgentDelegation, + {"agent_name": "prompt-agent-test", "agent_version": "7"}, + {"type": "foundry_managed_agent", "agent_name": "prompt-agent-test", "agent_version": "7"}, + id="foundry_managed_agent", + ), +] + + +def _definition_payload(delegation): + return { + "kind": "voice", + "sub_protocol": "live", + "model_type": "self_deployed", + "model": "live-deployment-test", + "instructions": "Delegate the spoken question.", + "store": False, + "audio": { + "format": {"type": "audio/pcm", "rate": 24000}, + "output": {"voice": "marin"}, + }, + "delegation": delegation, + } + + +@pytest.mark.parametrize("delegation_type,kwargs,payload", _DELEGATIONS) +def test_live_delegation_writable_json_roundtrip(delegation_type, kwargs, payload): + delegation = delegation_type(**kwargs) + writable = delegation.as_dict(exclude_readonly=True) + assert writable == payload + restored = delegation_type(json.loads(json.dumps(writable))) + assert restored.as_dict() == payload + assert restored.type == payload["type"] + if "acknowledgement_delay_ms" in payload: + assert restored.acknowledgement_delay_ms == 0 + else: + assert restored.agent_name == "prompt-agent-test" + assert restored.agent_version == "7" + + +@pytest.mark.parametrize("delegation_type,kwargs,payload", _DELEGATIONS) +def test_live_definition_writable_json_roundtrip(delegation_type, kwargs, payload): + definition = models.VoiceAgentLiveDefinition( + model_type=models.VoiceModelType.SELF_DEPLOYED, + model="live-deployment-test", + instructions="Delegate the spoken question.", + store=False, + audio=models.LiveInitialSessionAudioParam( + format=models.LiveSessionAudioFormatPCMParam(rate=24000), + output=models.LiveInitialSessionAudioOutputParam(voice="marin"), + ), + delegation=delegation_type(**kwargs), + ) + expected = _definition_payload(payload) + assert definition.as_dict(exclude_readonly=True) == expected + + restored = models.VoiceAgentLiveDefinition(json.loads(json.dumps(expected))) + assert restored.kind == "voice" + assert restored.sub_protocol == "live" + assert restored.model_type == "self_deployed" + assert restored.store is False + assert isinstance(restored.audio, models.LiveInitialSessionAudioParam) + assert isinstance(restored.audio.format, models.LiveSessionAudioFormatPCMParam) + assert restored.audio.format.rate == 24000 + assert isinstance(restored.delegation, delegation_type) + assert restored.delegation.as_dict() == payload + assert restored.as_dict() == expected + + +@pytest.mark.parametrize("delegation_type,kwargs,payload", _DELEGATIONS) +def test_live_agent_version_readback_uses_both_native_discriminators(delegation_type, kwargs, payload): + wire = { + "object": "agent.version", + "id": "live-agent-test:3", + "name": "live-agent-test", + "version": "3", + "created_at": 1700000000, + "metadata": {}, + "definition": _definition_payload(payload), + } + version = models.AgentVersionDetails(json.loads(json.dumps(wire))) + assert isinstance(version.definition, models.VoiceAgentLiveDefinition) + assert version.definition.kind == "voice" + assert version.definition.sub_protocol == "live" + assert version.definition.model_type == "self_deployed" + assert isinstance(version.definition.delegation, delegation_type) + assert version.definition.delegation.as_dict() == delegation_type(**kwargs).as_dict() == payload + assert version.as_dict() == wire + if "acknowledgement_delay_ms" in payload: + assert version.definition.delegation.acknowledgement_delay_ms == 0 + else: + assert version.definition.delegation.agent_name == "prompt-agent-test" + assert version.definition.delegation.agent_version == "7" + + +@pytest.mark.parametrize("agent_version", [None, "7"], ids=["active-version", "pinned-version"]) +def test_live_managed_agent_delegation_keeps_optional_version(agent_version): + kwargs = {"agent_name": "prompt-agent-test"} + expected = {"type": "foundry_managed_agent", **kwargs} + if agent_version is not None: + kwargs["agent_version"] = agent_version + expected["agent_version"] = agent_version + definition = models.VoiceAgentLiveDefinition( + model_type="self_deployed", + model="live-deployment-test", + delegation=models.VoiceAgentLiveManagedAgentDelegation(**kwargs), + ) + writable = json.loads(json.dumps(definition.as_dict(exclude_readonly=True))) + assert writable["delegation"] == expected + restored = models.VoiceAgentLiveDefinition(writable) + assert isinstance(restored.delegation, models.VoiceAgentLiveManagedAgentDelegation) + assert restored.delegation.type == "foundry_managed_agent" + assert restored.delegation.agent_version == agent_version diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_operation_exports.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_operation_exports.py new file mode 100644 index 000000000000..ffa316fa8183 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_operation_exports.py @@ -0,0 +1,28 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Unit tests for public sync and async voice-agent operation exports.""" + +from importlib import import_module +import inspect +from typing import get_type_hints +from unittest.mock import MagicMock + +import pytest + + +@pytest.mark.parametrize("namespace", ["azure.ai.projects.operations", "azure.ai.projects.aio.operations"]) +def test_live_conversations_operation_export(namespace): + operations = import_module(namespace) + generated = import_module(f"{namespace}._operations") + operation_name = "BetaVoiceAgentsLiveConversationsOperations" + operation_type = getattr(operations, operation_name) + + assert operation_name in operations.__all__ + assert operation_type is getattr(generated, operation_name) + assert get_type_hints(operations.BetaVoiceAgentsOperations)["live_conversations"] is operation_type + + voice_agents = operations.BetaVoiceAgentsOperations(MagicMock(), MagicMock(), MagicMock(), MagicMock()) + assert isinstance(voice_agents.live_conversations, operation_type) + assert inspect.iscoroutinefunction(operation_type.get) == (".aio." in namespace) diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live.py index 2baf6a476c93..6ba42809a87b 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live.py @@ -195,7 +195,7 @@ def test_realtime_function_tool_call(self, **kwargs): Configures the agent with a ``get_weather`` function tool, sends a prompt that should trigger it, executes the tool call locally when the service asks for it, and sends the result back so the agent can finish its reply -- mirroring - ``samples/agents/voice/sample_voice_agent_live_function_tool.py``, which this test + ``samples/agents/voice/sample_voice_agent_realtime_function_tool_async.py``, which this test adapts into an automated assertion-based form. """ print("\n") diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live_async.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live_async.py index 4feef324eda4..2eac89d8fc63 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live_async.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live_async.py @@ -191,7 +191,7 @@ async def test_realtime_function_tool_call_async(self, **kwargs): Configures the agent with a ``get_weather`` function tool, sends a prompt that should trigger it, executes the tool call locally when the service asks for it, and sends the result back so the agent can finish its reply -- the async counterpart of - ``sample_voice_agent_live_function_tool.py``'s pattern, adapted into an automated + ``sample_voice_agent_realtime_function_tool_async.py``'s pattern, adapted into an automated assertion-based test. """ print("\n") diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py index 335bfb4fa1cf..52bf81f5872c 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py @@ -12,8 +12,7 @@ from azure.core.exceptions import HttpResponseError, ResourceNotFoundError from azure.ai.projects.models import ( AgentVersionDetails, - PSTNTelephonyTransferDestination, - TelephonyBindingStatus, + PhoneNumber, TelephonyTransferTarget, TelephonyTransferTargets, UpdateTelephonyBindingRequest, @@ -27,7 +26,7 @@ class TestVoiceAgentTelephony(TestBase): """ Recorded tests covering the voice-agent telephony REST API surface exposed through - `project_client.agents.*` (telephony bindings, calls, and transfer targets), and the + `project_client.beta.voice_agents.telephony.*` (bindings, calls, and transfer targets), and the top-level `project_client.beta.voice_agents.conversations.*` generated-audio reads. NOTE: All tests in this file are currently marked `skip`: @@ -92,12 +91,12 @@ def test_telephony_bindings_and_transfer_targets(self, **kwargs): Action REST API Route Client Method ------+-------------------------------------------------------------+----------------------------------------------- POST /agents/{agent_name}/versions project_client.agents.create_version() - GET /agents/{agent_name}/telephony_bindings project_client.beta.voice_agents.telephony.list_bindings() - GET /agents/{agent_name}/telephony_transfer_targets project_client.beta.voice_agents.telephony.get_transfer_targets() - PUT /agents/{agent_name}/telephony_transfer_targets project_client.beta.voice_agents.telephony.replace_transfer_targets() - GET /agents/{agent_name}/telephony_bindings/{binding_id} project_client.beta.voice_agents.telephony.get_binding() - PATCH /agents/{agent_name}/telephony_bindings/{binding_id} project_client.beta.voice_agents.telephony.update_binding() - DELETE /agents/{agent_name}/telephony_bindings/{binding_id} project_client.beta.voice_agents.telephony.delete_binding() + GET /agents/{agent_name}/telephony/bindings project_client.beta.voice_agents.telephony.list_bindings() + GET /agents/{agent_name}/telephony/transfer_targets project_client.beta.voice_agents.telephony.get_transfer_targets() + PUT /agents/{agent_name}/telephony/transfer_targets project_client.beta.voice_agents.telephony.replace_transfer_targets() + GET /agents/{agent_name}/telephony/bindings/{binding_id} project_client.beta.voice_agents.telephony.get_binding() + PATCH /agents/{agent_name}/telephony/bindings/{binding_id} project_client.beta.voice_agents.telephony.update_binding() + DELETE /agents/{agent_name}/telephony/bindings/{binding_id} project_client.beta.voice_agents.telephony.delete_binding() DELETE /agents/{agent_name} project_client.agents.delete() """ print("\n") @@ -134,7 +133,7 @@ def test_telephony_bindings_and_transfer_targets(self, **kwargs): new_target = TelephonyTransferTarget( name="sales_desk", description="Transfers to the sales desk for pricing questions.", - destination=PSTNTelephonyTransferDestination(value="+14255550123"), + destination=PhoneNumber(value="+14255550123"), ) replaced_targets: TelephonyTransferTargets = ( project_client.beta.voice_agents.telephony.replace_transfer_targets( @@ -146,7 +145,9 @@ def test_telephony_bindings_and_transfer_targets(self, **kwargs): ) assert len(replaced_targets.transfer_targets) == 1 assert replaced_targets.transfer_targets[0].name == "sales_desk" - assert replaced_targets.transfer_targets[0].destination.kind == "pstn" + assert isinstance(replaced_targets.transfer_targets[0].destination, PhoneNumber) + assert replaced_targets.transfer_targets[0].destination.type == "phone_number" + assert replaced_targets.transfer_targets[0].destination.value == "+14255550123" # Confirm the change persisted. confirmed_targets: TelephonyTransferTargets = project_client.beta.voice_agents.telephony.get_transfer_targets( @@ -172,7 +173,7 @@ def test_telephony_bindings_and_transfer_targets(self, **kwargs): project_client.beta.voice_agents.telephony.update_binding( agent_name=agent_name, binding_id=fake_binding_id, - body=UpdateTelephonyBindingRequest(status=TelephonyBindingStatus.SUSPENDED), + body=UpdateTelephonyBindingRequest(label="Updated test binding"), etag=None, match_condition=MatchConditions.IfPresent, ) @@ -206,10 +207,10 @@ def test_telephony_calls_not_found(self, **kwargs): Action REST API Route Client Method ------+-------------------------------------------------------------+----------------------------------------------- POST /agents/{agent_name}/versions project_client.agents.create_version() - GET /agents/{agent_name}/telephony_calls project_client.beta.voice_agents.telephony.list_calls() - GET /agents/{agent_name}/telephony_calls/{call_id} project_client.beta.voice_agents.telephony.get_call() - POST /agents/{agent_name}/telephony_calls/{call_id}:transfer project_client.beta.voice_agents.telephony.transfer_call() - POST /agents/{agent_name}/telephony_calls/{call_id}:end project_client.beta.voice_agents.telephony.end_call() + GET /agents/{agent_name}/telephony/calls project_client.beta.voice_agents.telephony.list_calls() + GET /agents/{agent_name}/telephony/calls/{call_id} project_client.beta.voice_agents.telephony.get_call() + POST /agents/{agent_name}/telephony/calls/{call_id}:transfer project_client.beta.voice_agents.telephony.transfer_call() + POST /agents/{agent_name}/telephony/calls/{call_id}:end project_client.beta.voice_agents.telephony.end_call() DELETE /agents/{agent_name} project_client.agents.delete() """ print("\n") diff --git a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py index 80652b970c67..449004578529 100644 --- a/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py +++ b/sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py @@ -12,8 +12,7 @@ from azure.core.exceptions import HttpResponseError, ResourceNotFoundError from azure.ai.projects.models import ( AgentVersionDetails, - PSTNTelephonyTransferDestination, - TelephonyBindingStatus, + PhoneNumber, TelephonyTransferTarget, TelephonyTransferTargets, UpdateTelephonyBindingRequest, @@ -27,7 +26,7 @@ class TestVoiceAgentTelephonyAsync(TestBase): """ Recorded tests covering the voice-agent telephony REST API surface exposed through - `project_client.agents.*` (telephony bindings, calls, and transfer targets), and the + `project_client.beta.voice_agents.telephony.*` (bindings, calls, and transfer targets), and the top-level `project_client.beta.voice_agents.conversations.*` generated-audio reads. NOTE: All tests in this file are currently marked `skip`: @@ -92,12 +91,12 @@ async def test_telephony_bindings_and_transfer_targets(self, **kwargs): Action REST API Route Client Method ------+-------------------------------------------------------------+----------------------------------------------- POST /agents/{agent_name}/versions project_client.agents.create_version() - GET /agents/{agent_name}/telephony_bindings project_client.beta.voice_agents.telephony.list_bindings() - GET /agents/{agent_name}/telephony_transfer_targets project_client.beta.voice_agents.telephony.get_transfer_targets() - PUT /agents/{agent_name}/telephony_transfer_targets project_client.beta.voice_agents.telephony.replace_transfer_targets() - GET /agents/{agent_name}/telephony_bindings/{binding_id} project_client.beta.voice_agents.telephony.get_binding() - PATCH /agents/{agent_name}/telephony_bindings/{binding_id} project_client.beta.voice_agents.telephony.update_binding() - DELETE /agents/{agent_name}/telephony_bindings/{binding_id} project_client.beta.voice_agents.telephony.delete_binding() + GET /agents/{agent_name}/telephony/bindings project_client.beta.voice_agents.telephony.list_bindings() + GET /agents/{agent_name}/telephony/transfer_targets project_client.beta.voice_agents.telephony.get_transfer_targets() + PUT /agents/{agent_name}/telephony/transfer_targets project_client.beta.voice_agents.telephony.replace_transfer_targets() + GET /agents/{agent_name}/telephony/bindings/{binding_id} project_client.beta.voice_agents.telephony.get_binding() + PATCH /agents/{agent_name}/telephony/bindings/{binding_id} project_client.beta.voice_agents.telephony.update_binding() + DELETE /agents/{agent_name}/telephony/bindings/{binding_id} project_client.beta.voice_agents.telephony.delete_binding() DELETE /agents/{agent_name} project_client.agents.delete() """ print("\n") @@ -134,7 +133,7 @@ async def test_telephony_bindings_and_transfer_targets(self, **kwargs): new_target = TelephonyTransferTarget( name="sales_desk", description="Transfers to the sales desk for pricing questions.", - destination=PSTNTelephonyTransferDestination(value="+14255550123"), + destination=PhoneNumber(value="+14255550123"), ) replaced_targets: TelephonyTransferTargets = ( await project_client.beta.voice_agents.telephony.replace_transfer_targets( @@ -146,7 +145,9 @@ async def test_telephony_bindings_and_transfer_targets(self, **kwargs): ) assert len(replaced_targets.transfer_targets) == 1 assert replaced_targets.transfer_targets[0].name == "sales_desk" - assert replaced_targets.transfer_targets[0].destination.kind == "pstn" + assert isinstance(replaced_targets.transfer_targets[0].destination, PhoneNumber) + assert replaced_targets.transfer_targets[0].destination.type == "phone_number" + assert replaced_targets.transfer_targets[0].destination.value == "+14255550123" # Confirm the change persisted. confirmed_targets: TelephonyTransferTargets = ( @@ -176,7 +177,7 @@ async def test_telephony_bindings_and_transfer_targets(self, **kwargs): await project_client.beta.voice_agents.telephony.update_binding( agent_name=agent_name, binding_id=fake_binding_id, - body=UpdateTelephonyBindingRequest(status=TelephonyBindingStatus.SUSPENDED), + body=UpdateTelephonyBindingRequest(label="Updated test binding"), etag=None, match_condition=MatchConditions.IfPresent, ) @@ -210,10 +211,10 @@ async def test_telephony_calls_not_found(self, **kwargs): Action REST API Route Client Method ------+-------------------------------------------------------------+----------------------------------------------- POST /agents/{agent_name}/versions project_client.agents.create_version() - GET /agents/{agent_name}/telephony_calls project_client.beta.voice_agents.telephony.list_calls() - GET /agents/{agent_name}/telephony_calls/{call_id} project_client.beta.voice_agents.telephony.get_call() - POST /agents/{agent_name}/telephony_calls/{call_id}:transfer project_client.beta.voice_agents.telephony.transfer_call() - POST /agents/{agent_name}/telephony_calls/{call_id}:end project_client.beta.voice_agents.telephony.end_call() + GET /agents/{agent_name}/telephony/calls project_client.beta.voice_agents.telephony.list_calls() + GET /agents/{agent_name}/telephony/calls/{call_id} project_client.beta.voice_agents.telephony.get_call() + POST /agents/{agent_name}/telephony/calls/{call_id}:transfer project_client.beta.voice_agents.telephony.transfer_call() + POST /agents/{agent_name}/telephony/calls/{call_id}:end project_client.beta.voice_agents.telephony.end_call() DELETE /agents/{agent_name} project_client.agents.delete() """ print("\n") diff --git a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol.py b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol.py index c3f6dada1fcf..9f7393a719d7 100644 --- a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol.py +++ b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol.py @@ -63,9 +63,9 @@ def client() -> Iterator[AIProjectClient]: # (method_name, expected HTTP method, expected static URL path -- fake string/required params are # always rendered as the literal "fake-value" by FoundryFeaturesHeaderTestBase._fake_for_param). _TELEPHONY_PROTOCOL_CASES: List[Tuple[str, str, str]] = [ - ("create_call_job", "POST", "/agents/fake-value/telephony/call_jobs"), - ("get_call_job", "GET", "/agents/fake-value/telephony/call_jobs/fake-value"), - ("cancel_call_job", "POST", "/agents/fake-value/telephony/call_jobs/fake-value:cancel"), + ("create_call_job", "POST", "/agents/fake-value/telephony_call_jobs"), + ("get_call_job", "GET", "/agents/fake-value/telephony_call_jobs/fake-value"), + ("cancel_call_job", "POST", "/agents/fake-value/telephony_call_jobs/fake-value:cancel"), ] diff --git a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol_async.py b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol_async.py index 3dfd987b8b78..325a4a34c512 100644 --- a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol_async.py +++ b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol_async.py @@ -54,9 +54,9 @@ def async_client() -> Iterator[AsyncAIProjectClient]: # (method_name, expected HTTP method, expected static URL path -- fake string/required params are # always rendered as the literal "fake-value" by FoundryFeaturesHeaderTestBase._fake_for_param). _TELEPHONY_PROTOCOL_CASES: List[Tuple[str, str, str]] = [ - ("create_call_job", "POST", "/agents/fake-value/telephony/call_jobs"), - ("get_call_job", "GET", "/agents/fake-value/telephony/call_jobs/fake-value"), - ("cancel_call_job", "POST", "/agents/fake-value/telephony/call_jobs/fake-value:cancel"), + ("create_call_job", "POST", "/agents/fake-value/telephony_call_jobs"), + ("get_call_job", "GET", "/agents/fake-value/telephony_call_jobs/fake-value"), + ("cancel_call_job", "POST", "/agents/fake-value/telephony_call_jobs/fake-value:cancel"), ] diff --git a/sdk/ai/azure-ai-projects/tests/recordings/agents/assets.json b/sdk/ai/azure-ai-projects/tests/recordings/agents/assets.json new file mode 100644 index 000000000000..19989ef4f5fd --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/recordings/agents/assets.json @@ -0,0 +1,6 @@ +{ + "AssetsRepo": "Azure/azure-sdk-assets", + "AssetsRepoPrefixPath": "python", + "TagPrefix": "python/ai/azure-ai-projects", + "Tag": "python/ai/azure-ai-projects_0923f8a02f" +} diff --git a/sdk/ai/azure-ai-projects/tests/samples/ci/run_samples.py b/sdk/ai/azure-ai-projects/tests/samples/ci/run_samples.py index 9d468f06b6b9..8b423ac5d471 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/ci/run_samples.py +++ b/sdk/ai/azure-ai-projects/tests/samples/ci/run_samples.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. """Run resolved sample pytest nodes against the Bicep-created project, without recording.""" diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_live_async_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_live_async_samples.py new file mode 100644 index 000000000000..7f0be5dc9664 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/samples/test_live_async_samples.py @@ -0,0 +1,305 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline execution of the async GPT Live text and function-tool samples.""" + +import asyncio +import json + +import pytest + +from azure.ai.projects import models +from test_live_samples import ( + _closed, + _load_module, + _response, + _started, + _text_response, + sample_environment, +) + +pytestmark = pytest.mark.asyncio +_SCENARIOS = ("text_conversation", "function_tool") + + +def _load_sample(monkeypatch, scenario): + return _load_module(monkeypatch, f"sample_voice_agent_live_{scenario}_async.py") + + +def _tool_call(**fields): + return { + "id": "function-item-test", + "type": "function_call", + "name": "get_weather", + "call_id": "canonical-call-test", + "arguments": '{"city":"Seattle"}', + "status": "completed", + **fields, + } + + +def _tool_cycle(call): + return [ + _response("response.output_item.done", item=call), + _response("response.completed", response={"status": "completed", "output": []}), + ] + + +def _assert_owned_cleanup(sample, environment): + client, connection = environment.async_client, environment.async_connection + agent_name = client.agents.create_version.call_args.kwargs["agent_name"] + assert agent_name.startswith("live-offline-") + client.beta.voice_agents.live.connect.assert_called_once_with( + agent_name=agent_name, agent_version="owned-version", store=False + ) + client.agents.delete_version.assert_awaited_once_with(agent_name=agent_name, agent_version="owned-version") + client.agents.delete.assert_not_called() + connection.session.close.assert_awaited_once_with() + connection.session.start.assert_not_called() + connection.response.cancel.assert_not_called() + client.beta.voice_agents.realtime.connect.assert_not_called() + client.beta.voice_agents.live.connect.return_value.__aexit__.assert_awaited_once() + client.__aexit__.assert_awaited_once() + credential = sample.DefaultAzureCredential.return_value + credential.__aenter__.assert_awaited_once() + credential.__aexit__.assert_awaited_once() + sample.AIProjectClient.assert_called_once_with( + endpoint="https://example.invalid/api/projects/offline", + credential=credential.__aenter__.return_value, + allow_preview=True, + ) + + +async def test_async_text_reuses_one_session_and_waits_for_each_completed_turn(monkeypatch, sample_environment, capsys): + sample = _load_sample(monkeypatch, "text_conversation") + connection = sample_environment.async_connection + prompts = ["My name is Ada.", "What is my name?"] + monkeypatch.setattr(sample, "TEXT_PROMPTS", prompts) + events = iter( + [ + {"type": "future.event"}, + _started(), + *_text_response("Hello, Ada."), + *_text_response("Your name is Ada."), + _closed(), + ] + ) + completed = 0 + submitted = [] + + async def receive(): + nonlocal completed + event = next(events) + if event.get("type") == "response.event" and event["event"]["type"] == "response.completed": + completed += 1 + if event.get("type") == "session.closed": + connection.session.close.assert_awaited_once() + return event + + async def submit(*, item): + assert completed == len(submitted) + submitted.append(item["content"][0]["text"]) + + async def respond(): + assert connection.response.create.await_count == completed + 1 + + connection.recv.side_effect = receive + connection.response.item.create.side_effect = submit + connection.response.create.side_effect = respond + + await sample.main() + + assert submitted == prompts + assert completed == 2 + assert connection.response.create.await_count == 2 + sample_environment.async_client.agents.create_version.assert_awaited_once() + _assert_owned_cleanup(sample, sample_environment) + output = capsys.readouterr().out + assert output.count("Responses backend: Hello, Ada.\n") == 1 + assert output.count("Responses backend: Your name is Ada.\n") == 1 + assert "Session closed: close_requested" in output + + +async def test_async_function_uses_canonical_call_id_after_each_completed_cycle( + monkeypatch, sample_environment, capsys +): + sample = _load_sample(monkeypatch, "function_tool") + connection = sample_environment.async_connection + call = _tool_call() + events = iter( + [ + _started(), + _response("response.output_item.added", item={**call, "arguments": "", "status": "in_progress"}), + _response("response.function_call_arguments.delta", item_id=call["id"], delta='{"city":'), + _response("response.function_call_arguments.delta", item_id=call["id"], delta='"Seattle"}'), + _response( + "response.function_call_arguments.done", + item_id=call["id"], + name="get_weather", + arguments=call["arguments"], + ), + _response("response.output_item.done", item=call), + *_tool_cycle(call), + *_text_response("Here is the tool's sample forecast."), + _closed(), + ] + ) + completed = 0 + submitted = [] + + async def receive(): + nonlocal completed + event = next(events) + if event.get("type") == "response.event" and event["event"]["type"] == "response.completed": + completed += 1 + if event.get("type") == "session.closed": + connection.session.close.assert_awaited_once() + return event + + async def submit(*, item): + assert completed == len(submitted) + submitted.append(item) + + async def respond(): + assert connection.response.create.await_count == completed + 1 + + connection.recv.side_effect = receive + connection.response.item.create.side_effect = submit + connection.response.create.side_effect = respond + + await sample.main() + + assert completed == 2 + assert len(submitted) == 2 + assert submitted[0]["content"][0]["text"] == "Use get_weather for Seattle, then report the sample result." + assert submitted[1]["type"] == "function_call_output" + assert submitted[1]["call_id"] == call["call_id"] != call["id"] + assert json.loads(submitted[1]["output"]) == {"city": "Seattle", "condition": "sunny", "temperature_f": 72} + assert connection.response.create.await_count == 2 + definition = sample_environment.async_client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition, models.VoiceAgentLiveDefinition) + assert definition.model_type == models.VoiceModelType.SELF_DEPLOYED + assert definition.model == "live-deployment-test" + assert definition.store is False + assert isinstance(definition.delegation, models.VoiceAgentLiveResponsesDelegation) + responses = definition.delegation.responses + assert isinstance(responses, models.LiveResponsesDelegationSettingsInputParam) + assert responses.model == "backend-deployment-test" + assert responses.parallel_tool_calls is False + assert len(responses.tools) == 1 + assert isinstance(responses.tools[0], models.LiveFunctionToolInputParam) + assert responses.tools[0].name == "get_weather" + assert responses.tools[0].strict is True + _assert_owned_cleanup(sample, sample_environment) + assert "Responses backend: Here is the tool's sample forecast." in capsys.readouterr().out + + +async def test_async_function_rejects_a_repeated_call_in_a_later_cycle(monkeypatch, sample_environment): + sample = _load_sample(monkeypatch, "function_tool") + connection = sample_environment.async_connection + connection.recv.side_effect = [_started(), *_tool_cycle(_tool_call()), *_tool_cycle(_tool_call())] + + with pytest.raises(RuntimeError, match="missing or repeated function call ID"): + await sample.main() + + assert connection.response.item.create.await_count == 2 + assert connection.response.create.await_count == 2 + _assert_owned_cleanup(sample, sample_environment) + + +async def test_async_function_bounds_the_number_of_response_cycles(monkeypatch, sample_environment): + sample = _load_sample(monkeypatch, "function_tool") + connection = sample_environment.async_connection + events = [_started()] + for index in range(6): + events.extend(_tool_cycle(_tool_call(call_id=f"call-{index}"))) + connection.recv.side_effect = events + + with pytest.raises(RuntimeError, match="six-response tool-call limit"): + await sample.main() + + assert connection.response.item.create.await_count == 7 + assert connection.response.create.await_count == 7 + _assert_owned_cleanup(sample, sample_environment) + + +@pytest.mark.parametrize("scenario", _SCENARIOS) +@pytest.mark.parametrize( + "event,match", + [ + ({"type": "error", "error": {"code": "invalid_command", "message": "rejected"}}, "invalid_command: rejected"), + (_response("response.failed", response={"status": "failed"}), "Responses backend response.failed"), + ], +) +async def test_async_samples_propagate_service_failures(monkeypatch, sample_environment, scenario, event, match): + sample = _load_sample(monkeypatch, scenario) + sample_environment.async_connection.recv.side_effect = [_started(), event] + + with pytest.raises(RuntimeError, match=match): + await sample.main() + + _assert_owned_cleanup(sample, sample_environment) + + +@pytest.mark.parametrize("scenario", _SCENARIOS) +@pytest.mark.parametrize("failure", [RuntimeError("create failed")]) +async def test_async_samples_do_not_delete_versions_when_creation_fails( + monkeypatch, sample_environment, scenario, failure +): + sample = _load_sample(monkeypatch, scenario) + client = sample_environment.async_client + client.agents.create_version.side_effect = failure + + with pytest.raises(type(failure)): + await sample.main() + + client.agents.delete_version.assert_not_awaited() + client.agents.delete.assert_not_called() + client.beta.voice_agents.live.connect.assert_not_called() + client.__aexit__.assert_awaited_once() + sample.DefaultAzureCredential.return_value.__aexit__.assert_awaited_once() + + +@pytest.mark.parametrize("scenario", _SCENARIOS) +async def test_async_samples_delete_owned_version_if_connect_fails(monkeypatch, sample_environment, scenario): + sample = _load_sample(monkeypatch, scenario) + client = sample_environment.async_client + client.beta.voice_agents.live.connect.return_value.__aenter__.side_effect = ConnectionError("connect failed") + + with pytest.raises(ConnectionError, match="connect failed"): + await sample.main() + + agent_name = client.agents.create_version.call_args.kwargs["agent_name"] + client.agents.delete_version.assert_awaited_once_with(agent_name=agent_name, agent_version="owned-version") + client.agents.delete.assert_not_called() + sample_environment.async_connection.session.close.assert_not_awaited() + client.__aexit__.assert_awaited_once() + sample.DefaultAzureCredential.return_value.__aexit__.assert_awaited_once() + + +@pytest.mark.parametrize("scenario", _SCENARIOS) +@pytest.mark.parametrize("phase", ["response"]) +async def test_async_samples_preserve_cancellation_and_clean_up(monkeypatch, sample_environment, scenario, phase): + sample = _load_sample(monkeypatch, scenario) + connection = sample_environment.async_connection + receiving = asyncio.Event() + + async def receive(): + if phase == "response" and connection.recv.await_count == 1: + return _started() + receiving.set() + await asyncio.Future() + + connection.recv.side_effect = receive + connection.session.close.side_effect = ConnectionError("cleanup failed") + task = asyncio.create_task(sample.main()) + try: + await asyncio.wait_for(receiving.wait(), timeout=1) + finally: + task.cancel() + with pytest.raises(asyncio.CancelledError): + await task + + _assert_owned_cleanup(sample, sample_environment) + assert connection.response.create.await_count == (1 if phase == "response" else 0) diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_live_managed_agent_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_live_managed_agent_samples.py new file mode 100644 index 000000000000..979183b9ba39 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/samples/test_live_managed_agent_samples.py @@ -0,0 +1,516 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline workflow and cleanup checks for the managed prompt-agent Live sample.""" + +import asyncio +import base64 +from collections import deque +import importlib.util +import io +import json +from pathlib import Path +import sys +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock, call +import wave + +import pytest + +from azure.ai.projects import models + +_SAMPLES = Path(__file__).resolve().parents[2] / "samples" / "agents" / "voice" +_BACKEND = "owned-managed-backend-test" +_VOICE = "owned-managed-frontend-test" +_INPUT_PCM = b"\x00\x08" * 2400 +_OUTPUT_PCM = b"\x00\x09" * 1200 + + +def _load_module(monkeypatch, filename): + name = Path(filename).stem + spec = importlib.util.spec_from_file_location(name, _SAMPLES / filename) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + monkeypatch.setitem(sys.modules, name, module) + spec.loader.exec_module(module) + return module + + +def _wav_bytes(pcm=_INPUT_PCM, *, channels=1, rate=24000, sample_width=2): + stream = io.BytesIO() + with wave.open(stream, "wb") as recording: + recording.setnchannels(channels) + recording.setsampwidth(sample_width) + recording.setframerate(rate) + recording.writeframes(pcm) + return stream.getvalue() + + +def _snapshot(owner=None): + return { + "id": "session-managed-test", + "model": "gpt-live-1", + "expires_at": 2000000000, + "status": "active", + "delegation": ( + owner + if owner is not None + else {"type": "foundry_managed_agent", "agent_name": _BACKEND, "agent_version": "7"} + ), + } + + +def _started(owner=None): + return models.LiveServerEventLiveSessionStarted( + json.loads(json.dumps({"type": "session.started", "event_id": "started-test", "session": _snapshot(owner)})) + ) + + +def _closed(reason="close_requested"): + return models.LiveServerEventLiveSessionClosed( + json.loads( + json.dumps( + { + "type": "session.closed", + "event_id": "closed-test", + "session": _snapshot(), + "reason": reason, + "usage": {"seconds": 1}, + } + ) + ) + ) + + +def _delegated(target="foundry_managed_agent", delegation_id="delegation-test"): + return models.LiveServerEventLiveDelegationCreated( + json.loads( + json.dumps( + { + "type": "session.delegation.created", + "event_id": "delegated-test", + "offset_ms": 50, + "delegation": {"type": "delegation", "id": delegation_id, "target": target}, + } + ) + ) + ) + + +def _response(event_type="response.completed", *, delegation_id="delegation-test", **kwargs): + if event_type == "response.completed" and not kwargs: + kwargs = {"response": {"status": "completed", "output": []}} + return models.LiveServerEventLiveResponseEvent( + json.loads( + json.dumps( + { + "type": "response.event", + "event_id": "response-test", + "delegation_id": delegation_id, + "event": {"type": event_type, **kwargs}, + } + ) + ) + ) + + +def _audio(pcm=_OUTPUT_PCM): + return models.LiveOutputAudioDelta(delta=base64.b64encode(pcm).decode("ascii")) + + +def _transcript(text="Seattle has frequent rain."): + return models.LiveServerEventLiveOutputTranscriptDelta( + event_id="transcript-test", start_ms=100, end_ms=150, delta=text + ) + + +def _success_events(): + return [ + _delegated(), + # A server-owned backend tool event is observational, not a client request to execute it. + _response( + "response.output_item.added", + item={"type": "function_call", "name": "server_owned_tool", "call_id": "call-test"}, + ), + _response( + "response.output_text.delta", + item_id="backend-message-test", + content_index=0, + delta="[thinking]Preparing an answer.[commentary]Seattle has frequent rain.", + ), + _response(), + models.LiveServerEventLiveInputTranscriptDelta( + event_id="input-test", start_ms=0, end_ms=50, delta="Why does it rain in Seattle?" + ), + _audio(), + _transcript(), + ] + + +def _version(name, definition): + return models.AgentVersionDetails( + { + "object": "agent.version", + "id": f"{name}:7" if name == _BACKEND else f"{name}:11", + "name": name, + "version": "7" if name == _BACKEND else "11", + "created_at": 1700000000, + "metadata": {}, + "definition": definition.as_dict(), + } + ) + + +class _Clock: + def __init__(self): + self.now = 100.0 + + def monotonic(self): + return self.now + + def advance(self, seconds): + self.now += seconds + + +@pytest.fixture +def managed_sample(monkeypatch): + monkeypatch.syspath_prepend(str(_SAMPLES)) + monkeypatch.setenv("FOUNDRY_PROJECT_ENDPOINT", "https://example.invalid/api/projects/offline") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_MODEL", "live-deployment-test") + monkeypatch.setenv("FOUNDRY_MODEL_NAME", "prompt-deployment-test") + monkeypatch.setenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", "offline-managed-input.wav") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_NAME", "existing-agent-never-delete") + monkeypatch.setattr("dotenv.load_dotenv", lambda: False) + + shared = _load_module(monkeypatch, "live_sample_utils.py") + helper = _load_module(monkeypatch, "managed_agent_sample_utils.py") + clock = _Clock() + monkeypatch.setattr(shared, "time", clock) + monkeypatch.setattr(helper, "time", clock) + environment = SimpleNamespace( + is_async=True, + helper=helper, + clock=clock, + wav=_wav_bytes(), + events=deque([_started(), *_success_events()]), + sent=[], + received_during_input=[], + input_path="offline-managed-input.wav", + ) + real_wave_open = wave.open + + def open_input(path, mode): + assert path == environment.input_path and mode == "rb" + return real_wave_open(io.BytesIO(environment.wav), mode) + + monkeypatch.setattr(helper, "wave", SimpleNamespace(open=open_input, Error=wave.Error)) + connection = MagicMock() + + def send_audio(*, audio): + environment.sent.append((clock.monotonic(), audio)) + + def receive(timeout=0.05): + if environment.events: + clock.advance(0.005) + event = environment.events.popleft() + if isinstance(event, BaseException): + raise event + if environment.sent: + environment.received_during_input.append( + sum(len(chunk) for _, chunk in environment.sent) < len(_INPUT_PCM) + ) + return event + clock.advance(timeout) + raise TimeoutError("offline receive idle") + + def close(): + environment.events.append(_closed()) + + client = MagicMock() + credential = MagicMock() + manager = client.beta.voice_agents.live.connect.return_value + if environment.is_async: + client.__aenter__.return_value = client + credential.__aenter__.return_value = credential + manager.__aenter__.return_value = connection + client.agents.create_version = AsyncMock(side_effect=lambda **kw: _version(kw["agent_name"], kw["definition"])) + client.agents.delete_version = AsyncMock() + connection.recv = AsyncMock(side_effect=receive) + connection.session.input_audio.append = AsyncMock(side_effect=send_audio) + connection.session.close = AsyncMock(side_effect=close) + client_path = "azure.ai.projects.aio.AIProjectClient" + credential_path = "azure.identity.aio.DefaultAzureCredential" + else: + client.__enter__.return_value = client + credential.__enter__.return_value = credential + manager.__enter__.return_value = connection + client.agents.create_version.side_effect = lambda **kw: _version(kw["agent_name"], kw["definition"]) + connection.recv.side_effect = receive + connection.session.input_audio.append.side_effect = send_audio + connection.session.close.side_effect = close + client_path = "azure.ai.projects.AIProjectClient" + credential_path = "azure.identity.DefaultAzureCredential" + client_factory = MagicMock(return_value=client) + credential_factory = MagicMock(return_value=credential) + monkeypatch.setattr(client_path, client_factory) + monkeypatch.setattr(credential_path, credential_factory) + suffix = "_async" if environment.is_async else "" + sample = _load_module(monkeypatch, f"sample_voice_agent_live_managed_agent{suffix}.py") + monkeypatch.setattr( + sample, "sample_agent_name", lambda scenario: _BACKEND if scenario == "managed-backend" else _VOICE + ) + environment.sample = sample + environment.client = client + environment.client_factory = client_factory + environment.credential_factory = credential_factory + environment.connection = connection + environment.manager = manager + return environment + + +async def _run(environment): + if environment.is_async: + await environment.sample.main() + else: + environment.sample.main() + + +def _assert_deleted(environment, expected): + operation = environment.client.agents.delete_version + actual = operation.await_args_list if environment.is_async else operation.call_args_list + assert actual == [call(agent_name=name, agent_version=version) for name, version in expected] + environment.client.agents.delete.assert_not_called() + + +def _assert_no_client_delegation(environment): + connection = environment.connection + connection.response.item.create.assert_not_called() + connection.response.create.assert_not_called() + connection.response.cancel.assert_not_called() + connection.session.commentary.append.assert_not_called() + connection.session.thinking.append.assert_not_called() + connection.session.start.assert_not_called() + connection.session.update.assert_not_called() + connection.send.assert_not_called() + environment.client.beta.voice_agents.realtime.connect.assert_not_called() + + +@pytest.mark.asyncio +async def test_managed_samples_run_pinned_same_project_audio_workflow(managed_sample, capsys): + environment = managed_sample + await _run(environment) + + created = environment.client.agents.create_version.call_args_list + assert len(created) == 2 + backend = created[0].kwargs["definition"] + voice = created[1].kwargs["definition"] + assert created[0].kwargs["agent_name"] == _BACKEND + assert isinstance(backend, models.PromptAgentDefinition) + assert backend.model == "prompt-deployment-test" + assert "[thinking]" in backend.instructions and "[commentary]" in backend.instructions + assert created[1].kwargs["agent_name"] == _VOICE + assert isinstance(voice, models.VoiceAgentLiveDefinition) + assert voice.sub_protocol == "live" and voice.model_type == "self_deployed" + assert voice.model == "live-deployment-test" and voice.store is False + assert isinstance(voice.delegation, models.VoiceAgentLiveManagedAgentDelegation) + assert voice.delegation.as_dict() == { + "type": "foundry_managed_agent", + "agent_name": _BACKEND, + "agent_version": "7", + } + assert voice.audio.format.rate == 24000 and voice.audio.output.voice == "marin" + environment.client_factory.assert_called_once_with( + endpoint="https://example.invalid/api/projects/offline", + credential=environment.credential_factory.return_value, + allow_preview=True, + ) + environment.client.beta.voice_agents.live.connect.assert_called_once_with( + agent_name=_VOICE, agent_version="11", store=False + ) + sent = environment.sent + assert b"".join(chunk for _, chunk in sent[:2]) == _INPUT_PCM + assert len(sent) > 2 and all(not any(chunk) for _, chunk in sent[2:]) + assert all(not chunk.startswith(b"RIFF") for _, chunk in sent) + for (previous, chunk), (following, _) in zip(sent, sent[1:]): + assert following - previous >= len(chunk) / 48000 - 1e-8 + assert any(environment.received_during_input) + _assert_no_client_delegation(environment) + _assert_deleted(environment, [(_VOICE, "11"), (_BACKEND, "7")]) + environment.connection.session.close.assert_called_once() + if environment.is_async: + environment.connection.session.close.assert_awaited_once() + environment.manager.__aexit__.assert_awaited_once() + environment.client.__aexit__.assert_awaited_once() + else: + environment.manager.__exit__.assert_called_once() + environment.client.__exit__.assert_called_once() + text = capsys.readouterr().out + assert "target=foundry_managed_agent" in text + assert f"prompt agent {_BACKEND}, version 7" in text + assert "Output transcript: Seattle has frequent rain." in text + assert f"Received {len(_OUTPUT_PCM)} PCM16 bytes" in text + assert "not a playback-complete event" in text + + +@pytest.mark.asyncio +async def test_managed_sample_uses_bundled_audio_without_an_input_path_setting(managed_sample, monkeypatch): + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", raising=False) + managed_sample.input_path = str(_SAMPLES / "audio" / "question.wav") + + await _run(managed_sample) + + assert managed_sample.sent + _assert_deleted(managed_sample, [(_VOICE, "11"), (_BACKEND, "7")]) + + +@pytest.mark.asyncio +async def test_managed_samples_clock_silence_after_actual_input_send_finishes(managed_sample, monkeypatch): + environment = managed_sample + monkeypatch.setattr(environment.helper, "OUTPUT_IDLE_SECONDS", 0) + append = environment.connection.session.input_audio.append + original_send = append.side_effect + + def delayed_send(*, audio): + if len(environment.sent) < 2: + environment.clock.advance(0.75) + original_send(audio=audio) + + append.side_effect = delayed_send + await _run(environment) + + last_input_sent, last_input_chunk = environment.sent[1] + assert environment.clock.monotonic() >= last_input_sent + len(last_input_chunk) / 48000 + 1 + assert len(environment.sent) > 2 + assert all(not any(chunk) for _, chunk in environment.sent[2:]) + _assert_no_client_delegation(environment) + _assert_deleted(environment, [(_VOICE, "11"), (_BACKEND, "7")]) + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "invalid", + ["stereo", "silent", "truncated"], +) +async def test_managed_samples_validate_complete_wav_before_resource_creation(managed_sample, invalid): + environment = managed_sample + environment.wav = { + "stereo": lambda: _wav_bytes(channels=2), + "wrong-rate": lambda: _wav_bytes(rate=16000), + "wrong-width": lambda: _wav_bytes(sample_width=1), + "empty": lambda: _wav_bytes(b""), + "silent": lambda: _wav_bytes(bytes(4800)), + "truncated": lambda: _wav_bytes()[:-2], + "partial-frame": lambda: _wav_bytes(b"\x00\x08\x00"), + "too-long": lambda: _wav_bytes(b"\x00\x08" * (24000 * 31)), + "not-wav": lambda: b"not a WAV recording", + }[invalid]() + + with pytest.raises(ValueError, match="WAV|PCM16|audible"): + await _run(environment) + + environment.credential_factory.assert_not_called() + environment.client_factory.assert_not_called() + environment.client.agents.create_version.assert_not_called() + _assert_deleted(environment, []) + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "owner", + [ + pytest.param({"type": "client"}, id="client-owner"), + pytest.param( + {"type": "foundry_managed_agent", "agent_name": _BACKEND, "agent_version": "8"}, + id="wrong-version", + ), + ], +) +async def test_managed_samples_check_effective_owner_before_sending_audio(managed_sample, owner): + environment = managed_sample + environment.events[0] = _started(owner) + with pytest.raises(RuntimeError, match="pin the expected"): + await _run(environment) + assert not environment.sent + _assert_no_client_delegation(environment) + _assert_deleted(environment, [(_VOICE, "11"), (_BACKEND, "7")]) + + +_ERROR_EVENTS = [ + *[ + pytest.param( + _response(f"response.{status}", response={"status": status, "error": {"message": "Backend stopped"}}), + RuntimeError, + "Responses backend", + id=status, + ) + for status in ("failed", "incomplete", "cancelled") + ] +] + + +@pytest.mark.asyncio +@pytest.mark.parametrize("event,error_type,message", _ERROR_EVENTS) +async def test_managed_samples_propagate_backend_and_protocol_failures(managed_sample, event, error_type, message): + environment = managed_sample + environment.events = deque([_started(), _delegated(), event]) + with pytest.raises(error_type, match=message): + await _run(environment) + _assert_no_client_delegation(environment) + _assert_deleted(environment, [(_VOICE, "11"), (_BACKEND, "7")]) + environment.connection.session.close.assert_called_once() + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "events", + [ + pytest.param([_delegated(), _response()], id="backend-completion-only"), + pytest.param([_delegated(), _response(), _audio(bytes(2400)), _transcript()], id="silent-output"), + pytest.param([_delegated(), _response(), _audio()], id="missing-transcript"), + ], +) +async def test_managed_samples_never_treat_backend_completion_as_frontend_success( + managed_sample, monkeypatch, events, capsys +): + environment = managed_sample + monkeypatch.setattr(environment.helper, "RESPONSE_TIMEOUT", 2) + monkeypatch.setattr(environment.helper, "OUTPUT_IDLE_SECONDS", 0.1) + environment.events = deque([_started(), *events]) + with pytest.raises(TimeoutError, match="managed backend completion and nonempty Live audio/transcript"): + await _run(environment) + assert "Deleted only the Live and prompt-agent versions" not in capsys.readouterr().out + _assert_no_client_delegation(environment) + _assert_deleted(environment, [(_VOICE, "11"), (_BACKEND, "7")]) + assert any(not any(chunk) for _, chunk in environment.sent[2:]) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("stage", ["backend", "voice"]) +async def test_managed_samples_clean_only_successfully_created_versions(managed_sample, stage): + environment = managed_sample + error = RuntimeError(f"{stage} create failed") + results = [error] if stage == "backend" else [_version(_BACKEND, models.PromptAgentDefinition(model="test")), error] + environment.client.agents.create_version.side_effect = results + with pytest.raises(RuntimeError, match=f"{stage} create failed"): + await _run(environment) + environment.client.beta.voice_agents.live.connect.assert_not_called() + _assert_deleted(environment, [] if stage == "backend" else [(_BACKEND, "7")]) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("stage", ["stream"]) +async def test_managed_samples_cleanup_on_cancellation_without_swallowing_it(managed_sample, stage): + environment = managed_sample + cancellation = asyncio.CancelledError() if environment.is_async else KeyboardInterrupt() + if stage == "voice-create": + environment.client.agents.create_version.side_effect = [ + _version(_BACKEND, models.PromptAgentDefinition(model="test")), + cancellation, + ] + else: + environment.events = deque([_started(), _delegated(), cancellation]) + with pytest.raises(type(cancellation)): + await _run(environment) + _assert_deleted(environment, [(_BACKEND, "7")] if stage == "voice-create" else [(_VOICE, "11"), (_BACKEND, "7")]) + _assert_no_client_delegation(environment) diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_live_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_live_samples.py new file mode 100644 index 000000000000..33cbd31635fe --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/samples/test_live_samples.py @@ -0,0 +1,1642 @@ +# pylint: disable=too-many-lines +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline guards for the GPT Live sample protocol, cleanup, and WAV handling.""" + +import asyncio +import base64 +from concurrent.futures import Future +import importlib.util +import io +import json +from pathlib import Path +import queue +import sys +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock +import wave + +import pytest +from azure.core.exceptions import HttpResponseError + +from azure.ai.projects import models + +_SAMPLE_DIRECTORY = Path(__file__).resolve().parents[2] / "samples" / "agents" / "voice" +_ASYNC_SCENARIOS = ("connection", "text_conversation", "function_tool") + + +def _load_module(monkeypatch, filename): + name = Path(filename).stem + spec = importlib.util.spec_from_file_location(name, _SAMPLE_DIRECTORY / filename) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + monkeypatch.setitem(sys.modules, name, module) + spec.loader.exec_module(module) + return module + + +def _started(): + return models.LiveServerEventLiveSessionStarted({"event_id": "start-test", "session": {"id": "session-test"}}) + + +def _closed(): + return models.LiveServerEventLiveSessionClosed( + { + "event_id": "closed-test", + "reason": "close_requested", + "session": {"id": "session-test"}, + "usage": {"seconds": 1}, + } + ) + + +def _response(event_type, **fields): + return models.LiveServerEventLiveResponseEvent(event_id="response-event-test", event={"type": event_type, **fields}) + + +def _text_response(text): + return [ + _response("response.output_text.delta", item_id="message-test", content_index=0, delta=text), + _response("response.output_text.done", item_id="message-test", content_index=0, text=text), + _response("response.completed", response={"status": "completed", "output": []}), + ] + + +def _recording(payload=b"\x01\x00" * 1200, *, channels=1, rate=24000, sample_width=2): + stream = io.BytesIO() + with wave.open(stream, "wb") as writer: + writer.setnchannels(channels) + writer.setsampwidth(sample_width) + writer.setframerate(rate) + writer.writeframes(payload) + stream.seek(0) + return wave.open(stream, "rb") + + +def _capture_sample_output_directories(monkeypatch, sample, tmp_path): + make_directory = sample.mkdtemp + directories = [] + + def create_directory(*, prefix): + directory = Path(make_directory(prefix=prefix, dir=tmp_path)) + directories.append(directory) + return str(directory) + + factory = MagicMock(side_effect=create_directory) + monkeypatch.setattr(sample, "mkdtemp", factory) + return factory, directories + + +@pytest.fixture +def sample_environment(monkeypatch): + monkeypatch.setenv("FOUNDRY_PROJECT_ENDPOINT", "https://example.invalid/api/projects/offline") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_MODEL", "live-deployment-test") + monkeypatch.setenv("FOUNDRY_MODEL_NAME", "backend-deployment-test") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_NAME", "live-offline") + monkeypatch.setenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", "offline-input.wav") + monkeypatch.setattr("dotenv.load_dotenv", lambda: False) + + client = MagicMock() + client.__enter__.return_value = client + client.agents.create_version.return_value = SimpleNamespace(version="owned-version") + connection = client.beta.voice_agents.live.connect.return_value.__enter__.return_value + monkeypatch.setattr("azure.ai.projects.AIProjectClient", MagicMock(return_value=client)) + monkeypatch.setattr("azure.identity.DefaultAzureCredential", MagicMock()) + + async_client = MagicMock() + async_client.__aenter__.return_value = async_client + async_client.agents.create_version = AsyncMock(return_value=SimpleNamespace(version="owned-version")) + async_client.agents.delete_version = AsyncMock() + async_connection = async_client.beta.voice_agents.live.connect.return_value.__aenter__.return_value + async_connection.recv = AsyncMock() + async_connection.session.update = AsyncMock() + async_connection.session.instructions.append = AsyncMock() + async_connection.session.close = AsyncMock() + async_connection.session.input_audio.append = AsyncMock() + async_connection.session.commentary.append = AsyncMock() + async_connection.response.item.create = AsyncMock() + async_connection.response.create = AsyncMock() + monkeypatch.setattr("azure.ai.projects.aio.AIProjectClient", MagicMock(return_value=async_client)) + monkeypatch.setattr("azure.identity.aio.DefaultAzureCredential", MagicMock()) + + helper = _load_module(monkeypatch, "live_sample_utils.py") + return SimpleNamespace( + client=client, + connection=connection, + async_client=async_client, + async_connection=async_connection, + helper=helper, + ) + + +@pytest.mark.parametrize("scenario", _ASYNC_SCENARIOS) +@pytest.mark.asyncio +async def test_async_samples_delete_only_the_owned_version_on_failure(monkeypatch, sample_environment, scenario): + sample = _load_module(monkeypatch, f"sample_voice_agent_live_{scenario}_async.py") + client = sample_environment.async_client + connection = sample_environment.async_connection + connection.recv.side_effect = RuntimeError("offline receive failure") + connection.session.close.side_effect = ConnectionError("offline cleanup failure") + + with pytest.raises(RuntimeError, match="offline receive failure"): + await sample.main() + + agent_name = client.agents.create_version.call_args.kwargs["agent_name"] + assert agent_name.startswith("live-offline-") + client.beta.voice_agents.live.connect.assert_called_once_with( + agent_name=agent_name, agent_version="owned-version", store=False + ) + client.agents.delete_version.assert_awaited_once_with(agent_name=agent_name, agent_version="owned-version") + client.agents.delete.assert_not_called() + connection.session.close.assert_awaited_once() + connection.session.start.assert_not_called() + connection.response.cancel.assert_not_called() + client.beta.voice_agents.realtime.connect.assert_not_called() + client.beta.voice_agents.live.connect.return_value.__aexit__.assert_awaited_once() + + +@pytest.mark.parametrize("scenario", _ASYNC_SCENARIOS) +@pytest.mark.asyncio +async def test_failed_agent_creation_does_not_delete_an_existing_version(monkeypatch, sample_environment, scenario): + sample = _load_module(monkeypatch, f"sample_voice_agent_live_{scenario}_async.py") + sample_environment.async_client.agents.create_version.side_effect = RuntimeError("create failed") + + with pytest.raises(RuntimeError, match="create failed"): + await sample.main() + + sample_environment.async_client.agents.delete_version.assert_not_called() + sample_environment.async_client.beta.voice_agents.live.connect.assert_not_called() + + +def test_default_audio_is_usable_from_any_working_directory(monkeypatch, sample_environment, tmp_path): + helper = sample_environment.helper + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", raising=False) + monkeypatch.chdir(tmp_path) + + path = helper.input_audio_path() + with wave.open(str(path), "rb") as recording: + assert recording.getnchannels() == 1 + assert recording.getsampwidth() == 2 + assert recording.getframerate() == 24000 + assert 0 < recording.getnframes() <= 24000 * 30 + pcm = recording.readframes(recording.getnframes()) + assert any( + abs(int.from_bytes(pcm[index : index + 2], "little", signed=True)) > 256 for index in range(0, len(pcm), 2) + ) + + override = tmp_path / "my-question.wav" + monkeypatch.setenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", str(override)) + assert helper.input_audio_path() == override + + +@pytest.mark.asyncio +async def test_connection_waits_for_start_and_confirms_graceful_close(monkeypatch, sample_environment, capsys): + sample = _load_module(monkeypatch, "sample_voice_agent_live_connection_async.py") + connection = sample_environment.async_connection + connection.recv.side_effect = [ + {"type": "future.event"}, + _started(), + {"type": "session.updated"}, + {"type": "session.instructions.appended"}, + _closed(), + ] + + await sample.main() + + definition = sample_environment.async_client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition, models.VoiceAgentLiveDefinition) + assert definition.model == "live-deployment-test" + assert definition.sub_protocol == "live" + assert definition.model_type == "self_deployed" + assert isinstance(definition.delegation, models.VoiceAgentLiveClientDelegation) + assert definition.audio.format.rate == 24000 + assert definition.audio.output.voice == "marin" + session = connection.session.update.call_args.kwargs["session"] + assert isinstance(session, models.LiveSessionUpdateParams) + assert isinstance(session.delegation, models.LiveSessionUpdateParamsDelegationLiveClientDelegationParam) + connection.session.instructions.append.assert_awaited_once_with( + content="Keep responses brief. Do not invent external facts.", delegation_id=None + ) + connection.session.input_audio.append.assert_awaited_once_with(audio=bytes(2400)) + assert "Live session started: session-test" in capsys.readouterr().out + + +@pytest.mark.asyncio +async def test_context_ack_wait_sends_paced_silence_despite_receive_timeouts(monkeypatch, sample_environment): + helper = sample_environment.helper + clock = SimpleNamespace(now=0.0) + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=lambda: clock.now)) + connection = sample_environment.async_connection + sent = [] + connection.session.input_audio.append.side_effect = lambda *, audio: sent.append((clock.now, audio)) + calls = [] + + async def wait_for(awaitable, *, timeout): + calls.append(timeout) + clock.now += timeout + return await awaitable + + def receive(): + if len(calls) == 1: + raise TimeoutError + if len(calls) == 2: + return {"type": "future.event"} + return {"type": "session.instructions.appended"} + + connection.recv.side_effect = receive + monkeypatch.setattr(helper.asyncio, "wait_for", wait_for) + event = await helper.wait_for_event_with_audio_clock_async(connection, "session.instructions.appended") + + assert event["type"] == "session.instructions.appended" + assert [when for when, _ in sent] == pytest.approx([0.0, 0.05, 0.1]) + assert all(audio == bytes(2400) for _, audio in sent) + assert calls == pytest.approx([0.05, 0.05, 0.05]) + + +@pytest.mark.asyncio +async def test_context_ack_wait_does_not_send_audio_for_every_fast_server_event(monkeypatch, sample_environment): + helper = sample_environment.helper + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=lambda: 0.0)) + connection = sample_environment.async_connection + connection.recv.side_effect = [ + {"type": "future.event"}, + {"type": "session.usage.updated"}, + {"type": "session.instructions.appended"}, + ] + + await helper.wait_for_event_with_audio_clock_async(connection, "session.instructions.appended") + + connection.session.input_audio.append.assert_awaited_once_with(audio=bytes(2400)) + + +@pytest.mark.asyncio +async def test_context_ack_wait_keeps_one_overall_deadline(monkeypatch, sample_environment): + helper = sample_environment.helper + clock = SimpleNamespace(now=0.0) + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=lambda: clock.now)) + connection = sample_environment.async_connection + + async def wait_for(awaitable, *, timeout): + clock.now += timeout + return await awaitable + + connection.recv.side_effect = TimeoutError + monkeypatch.setattr(helper.asyncio, "wait_for", wait_for) + with pytest.raises(TimeoutError, match="session.instructions.appended"): + await helper.wait_for_event_with_audio_clock_async(connection, "session.instructions.appended", timeout=0.1) + + assert connection.session.input_audio.append.call_count == 2 + assert connection.recv.call_count == 2 + + +@pytest.mark.asyncio +async def test_context_ack_wait_surfaces_audio_send_failure(sample_environment): + connection = sample_environment.async_connection + connection.session.input_audio.append.side_effect = ConnectionError("clock send failed") + + with pytest.raises(ConnectionError, match="clock send failed"): + await sample_environment.helper.wait_for_event_with_audio_clock_async( + connection, "session.instructions.appended" + ) + connection.recv.assert_not_called() + + +@pytest.mark.parametrize( + "event,message", + [ + ({"type": "error", "error": {"code": "invalid_command", "message": "rejected"}}, "invalid_command"), + ({"type": "session.closed", "reason": "server_failure"}, "closed before"), + ], +) +@pytest.mark.asyncio +async def test_context_ack_wait_does_not_hide_service_errors(sample_environment, event, message): + connection = sample_environment.async_connection + connection.recv.return_value = event + + with pytest.raises(RuntimeError, match=message): + await sample_environment.helper.wait_for_event_with_audio_clock_async( + connection, "session.instructions.appended" + ) + + +@pytest.mark.asyncio +async def test_text_uses_responses_delegation_and_granular_text(monkeypatch, sample_environment, capsys): + sample = _load_module(monkeypatch, "sample_voice_agent_live_text_conversation_async.py") + connection = sample_environment.async_connection + connection.recv.side_effect = [_started(), *_text_response("Seattle has a rainy climate."), _closed()] + + await sample.main() + + definition = sample_environment.async_client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition.delegation, models.VoiceAgentLiveResponsesDelegation) + assert definition.delegation.responses.model == "backend-deployment-test" + item = connection.response.item.create.call_args.kwargs["item"] + assert item["type"] == "message" and item["role"] == "user" + assert item["content"][0]["type"] == "input_text" + connection.response.create.assert_awaited_once_with() + assert "Responses backend: Seattle has a rainy climate." in capsys.readouterr().out + + +@pytest.mark.asyncio +async def test_text_rejects_empty_backend_completion(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_text_conversation_async.py") + sample_environment.async_connection.recv.side_effect = [ + _started(), + _response("response.completed", response={"status": "completed", "output": []}), + ] + + with pytest.raises(RuntimeError, match="without returning any output text"): + await sample.main() + + sample_environment.async_client.agents.delete_version.assert_awaited_once() + + +@pytest.mark.parametrize("event_type", ["error", "response.failed", "response.incomplete", "response.cancelled"]) +def test_backend_failures_are_not_successful_completions(sample_environment, event_type): + with pytest.raises(RuntimeError, match="Responses backend"): + sample_environment.helper.check_event(_response(event_type, response={"error": {"message": "backend failed"}})) + + +def test_outer_live_errors_are_raised(sample_environment): + event = models.LiveServerEventLiveErrorEvent( + event_id="error-test", + error=models.LiveLiveError(type="invalid_request_error", code="invalid_command", message="command rejected"), + ) + with pytest.raises(RuntimeError, match="invalid_command: command rejected"): + sample_environment.helper.check_event(event) + + +def test_lifecycle_wait_has_one_deadline(monkeypatch, sample_environment): + helper = sample_environment.helper + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=MagicMock(side_effect=[0, 1, 61]))) + sample_environment.connection.recv.return_value = {"type": "future.event"} + + with pytest.raises(TimeoutError, match="session.started"): + helper.wait_for_event(sample_environment.connection, "session.started") + + sample_environment.connection.recv.assert_called_once_with(timeout=59) + + +@pytest.mark.asyncio +async def test_async_lifecycle_timeout_names_the_missing_event(sample_environment): + sample_environment.async_connection.recv.side_effect = asyncio.TimeoutError + with pytest.raises(TimeoutError, match="session.started"): + await sample_environment.helper.wait_for_event_async(sample_environment.async_connection, "session.started") + + +@pytest.mark.asyncio +async def test_async_close_send_is_bounded(monkeypatch, sample_environment): + monkeypatch.setattr(sample_environment.helper, "CLOSE_TIMEOUT", 0.01) + + async def stalled_close(): + await asyncio.Future() + + sample_environment.async_connection.session.close.side_effect = stalled_close + with pytest.raises(TimeoutError, match="closing the GPT Live session"): + await sample_environment.helper.close_session_async(sample_environment.async_connection) + sample_environment.async_connection.session.close.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_async_close_timeout_preserves_the_original_error(monkeypatch, sample_environment): + monkeypatch.setattr(sample_environment.helper, "CLOSE_TIMEOUT", 0.01) + + async def stalled_close(): + await asyncio.Future() + + sample_environment.async_connection.session.close.side_effect = stalled_close + with pytest.raises(RuntimeError, match="original receive failure"): + try: + raise RuntimeError("original receive failure") + finally: + await sample_environment.helper.close_session_async(sample_environment.async_connection) + sample_environment.async_connection.session.close.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_function_tool_waits_for_each_completed_cycle(monkeypatch, sample_environment, capsys): + sample = _load_module(monkeypatch, "sample_voice_agent_live_function_tool_async.py") + call = { + "id": "fc-item-test", + "type": "function_call", + "name": "get_weather", + "call_id": "call-test", + "arguments": '{"city":"Seattle"}', + "status": "completed", + } + connection = sample_environment.async_connection + connection.recv.side_effect = [ + _started(), + _response("response.output_item.added", item={**call, "arguments": "", "status": "in_progress"}), + _response("response.function_call_arguments.delta", item_id="fc-item-test", delta='{"city":'), + _response("response.function_call_arguments.delta", item_id="fc-item-test", delta='"Seattle"}'), + _response( + "response.function_call_arguments.done", + item_id="fc-item-test", + name="get_weather", + arguments='{"city":"Seattle"}', + ), + _response("response.output_item.done", item=call), + _response("response.output_item.done", item=call), + _response("response.completed", response={"status": "completed", "output": []}), + *_text_response("The sample weather in Seattle is sunny, 72 F."), + _closed(), + ] + + await sample.main() + + submitted = connection.response.item.create.call_args_list + assert len(submitted) == 2 + result = submitted[1].kwargs["item"] + assert result["type"] == "function_call_output" + assert result["call_id"] == "call-test" + assert json.loads(result["output"]) == {"city": "Seattle", "condition": "sunny", "temperature_f": 72} + assert connection.response.create.call_count == 2 + assert "Responses backend: The sample weather in Seattle is sunny, 72 F." in capsys.readouterr().out + + +def test_argument_done_without_call_id_does_not_invent_a_tool_call(sample_environment): + sample_environment.connection.recv.side_effect = [ + _response( + "response.function_call_arguments.done", + item_id="fc-item-test", + name="get_weather", + arguments='{"city":"Seattle"}', + ), + _response("response.completed", response={"status": "completed", "output": []}), + ] + + text, calls = sample_environment.helper.receive_response(sample_environment.connection) + + assert text == "" + assert calls == [] + + +def test_completed_function_call_requires_its_canonical_call_id(sample_environment): + sample_environment.connection.recv.return_value = _response( + "response.output_item.done", + item={"id": "fc-item-test", "type": "function_call", "name": "get_weather", "arguments": '{"city":"Seattle"}'}, + ) + + with pytest.raises(RuntimeError, match="function_call item omitted a usable call_id"): + sample_environment.helper.receive_response(sample_environment.connection) + + +@pytest.mark.parametrize("arguments", ['{"city":1}', '{"city":"Seattle","extra":true}', '["Seattle"]']) +def test_function_tool_rejects_invalid_arguments(monkeypatch, sample_environment, arguments): + sample = _load_module(monkeypatch, "sample_voice_agent_live_function_tool_async.py") + with pytest.raises(ValueError, match="exactly one string argument"): + sample._execute_tool({"name": "get_weather", "arguments": arguments}) + + +@pytest.mark.parametrize("options", [{"channels": 2}, {"rate": 16000}, {"sample_width": 1}, {"payload": b""}]) +def test_audio_rejects_wrong_or_empty_wav_before_connecting(monkeypatch, sample_environment, options): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + with _recording(**options) as recording: + with pytest.raises(ValueError, match="WAV|no audio frames"): + sample._validate_recording(recording) + sample_environment.async_client.beta.voice_agents.live.connect.assert_not_called() + + +@pytest.mark.asyncio +async def test_audio_streams_raw_frames_concurrently_and_collects_transcripts(monkeypatch, sample_environment, capsys): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + connection = sample_environment.async_connection + original_sleep = asyncio.sleep + + async def yield_without_delay(_delay): + await original_sleep(0) + + monkeypatch.setattr(sample.asyncio, "sleep", yield_without_delay) + monkeypatch.setattr(sample, "_OUTPUT_IDLE_SECONDS", 0) + payload = b"\x01\x00" * 2400 + reply = b"\x00\x08" * 1200 + events = iter( + [ + models.LiveServerEventLiveInputTranscriptDelta(event_id="input", start_ms=0, end_ms=50, delta="Hello."), + models.LiveOutputAudioDelta(delta=base64.b64encode(reply).decode("ascii")), + models.LiveServerEventLiveOutputTranscriptDelta(event_id="output", start_ms=0, end_ms=50, delta="Hi!"), + models.LiveServerEventLiveDelegationCreated( + event_id="delegation", + offset_ms=50, + delegation=models.VoiceAgentLiveDelegationItem(id="delegation-test", target="client"), + ), + ] + ) + received_during_send = [] + + async def receive(): + await original_sleep(0) + try: + event = next(events) + except StopIteration as exc: + raise asyncio.TimeoutError from exc + received_during_send.append(connection.session.input_audio.append.await_count < 22) + return event + + connection.recv.side_effect = receive + output_stream = io.BytesIO() + with _recording(payload) as recording, wave.open(output_stream, "wb") as output_file: + output_file.setparams((1, 2, 24000, 0, "NONE", "not compressed")) + await sample._stream_recording(connection, recording, output_file) + output_stream.seek(0) + with wave.open(output_stream, "rb") as recording: + assert recording.readframes(recording.getnframes()) == reply + sent = [call.kwargs["audio"] for call in connection.session.input_audio.append.await_args_list] + assert b"".join(sent[:2]) == payload + assert sum(map(len, sent)) == len(payload) + 48000 + assert all(not chunk.startswith(b"RIFF") for chunk in sent) + assert any(received_during_send) + connection.session.commentary.append.assert_awaited_once_with( + content="This sample cannot look up external information. Briefly acknowledge the recorded request.", + delegation_id="delegation-test", + ) + text = capsys.readouterr().out + assert "Input transcript: Hello." in text and "Output transcript: Hi!" in text + assert f"Received {len(reply)} PCM16 bytes" in text + + +@pytest.mark.asyncio +async def test_audio_send_failure_cancels_the_receiver(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + connection = sample_environment.async_connection + connection.session.input_audio.append.side_effect = ConnectionError("audio send failed") + receiver_stopped = asyncio.Event() + + async def receive(): + try: + await asyncio.Future() + finally: + receiver_stopped.set() + + connection.recv.side_effect = receive + with _recording() as recording: + with pytest.raises(ConnectionError, match="audio send failed"): + await sample._stream_recording(connection, recording, None) + assert receiver_stopped.is_set() + connection.response.cancel.assert_not_called() + + +@pytest.mark.asyncio +async def test_audio_cannot_complete_without_reply_bytes(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + finished = asyncio.Event() + finished.set() + with pytest.raises(TimeoutError, match="GPT Live reply audio"): + await sample._receive_audio(sample_environment.async_connection, finished, 0, None) + sample_environment.async_connection.recv.assert_not_awaited() + + +@pytest.mark.asyncio +async def test_audio_idle_completion_does_not_require_a_receive_timeout(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + monkeypatch.setattr(sample, "_OUTPUT_IDLE_SECONDS", 0) + finished = asyncio.Event() + finished.set() + reply = b"\x00\x08" * 1200 + sample_environment.async_connection.recv.return_value = models.LiveOutputAudioDelta( + delta=base64.b64encode(reply).decode("ascii") + ) + output = await sample._receive_audio(sample_environment.async_connection, finished, 1, None) + assert output.num_bytes == len(reply) + sample_environment.async_connection.recv.assert_awaited_once() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("delta", ["not valid base64", base64.b64encode(b"\x01").decode("ascii")]) +async def test_audio_rejects_invalid_or_partial_pcm(monkeypatch, sample_environment, delta): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + sample_environment.async_connection.recv.return_value = models.LiveOutputAudioDelta(delta=delta) + with pytest.raises(ValueError): + await sample._receive_audio(sample_environment.async_connection, asyncio.Event(), 1, None) + + +@pytest.mark.asyncio +@pytest.mark.parametrize("hard_link", [False, True], ids=["input-path", "hard-linked-input"]) +async def test_audio_temp_output_never_overwrites_input_audio(monkeypatch, sample_environment, tmp_path, hard_link): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + input_path = tmp_path / ("input.wav" if hard_link else "reply.wav") + output_path = tmp_path / "reply.wav" + original = _wav_bytes(1) + input_path.write_bytes(original) + if hard_link: + output_path.hardlink_to(input_path) + assert output_path.samefile(input_path) + monkeypatch.setenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", str(input_path)) + monkeypatch.setattr(sample, "SAVE_AUDIO", True) + monkeypatch.setattr(sample, "mkdtemp", MagicMock(return_value=str(tmp_path))) + monkeypatch.setattr(sample, "_run_audio_conversation", AsyncMock()) + + with pytest.raises(FileExistsError): + await sample.main() + + assert input_path.read_bytes() == original + assert output_path.read_bytes() == original + sample_environment.async_client.agents.create_version.assert_not_awaited() + sample_environment.async_client.beta.voice_agents.live.connect.assert_not_called() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("microphone", [False, True], ids=["wav", "microphone"]) +@pytest.mark.parametrize("save_audio", [False, True], ids=["no-recording", "save-reply"]) +async def test_audio_recording_is_opt_in_and_uses_unique_persistent_user_temp_folders( + monkeypatch, sample_environment, tmp_path, capsys, microphone, save_audio +): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + input_path = tmp_path / "input.wav" + original = _wav_bytes(1) + input_path.write_bytes(original) + if microphone: + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH") + else: + monkeypatch.setenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", str(input_path)) + monkeypatch.setattr(sample, "USE_MICROPHONE", microphone) + monkeypatch.setattr(sample, "SAVE_AUDIO", save_audio) + backend = object() + monkeypatch.setattr(sample, "_microphone_backend", lambda: backend) + output_factory, directories = _capture_sample_output_directories(monkeypatch, sample, tmp_path) + reply = b"\x00\x08" * 1200 + + async def stream(client, agent_name, agent_version, recording, output_file, *, audio_backend=None): + assert client is sample_environment.async_client + assert agent_version == "owned-version" + assert agent_name.startswith("live-offline-") + if microphone: + assert recording is None and audio_backend is backend + else: + assert recording.readframes(recording.getnframes()) == b"\x01\x02" * 1200 + if save_audio: + output_file.writeframesraw(reply) + else: + assert output_file is None + + run_audio = AsyncMock(side_effect=stream) + monkeypatch.setattr(sample, "_run_audio_conversation", run_audio) + await sample.main() + await sample.main() + + assert input_path.read_bytes() == original + assert run_audio.await_count == 2 + if save_audio: + assert len(directories) == 2 and directories[0] != directories[1] + assert output_factory.call_count == 2 + for directory in directories: + assert directory.parent == tmp_path + with wave.open(str(directory / "reply.wav"), "rb") as recording: + assert recording.getparams()[:3] == (1, 2, 24000) + assert recording.readframes(recording.getnframes()) == reply + output = capsys.readouterr().out + assert all(str(directory) in output for directory in directories) + else: + output_factory.assert_not_called() + assert directories == [] + assert sample_environment.async_client.agents.delete_version.await_count == 2 + sample_environment.async_client.agents.delete.assert_not_called() + + +@pytest.mark.asyncio +async def test_audio_temp_directory_failure_precedes_service_resource_creation( + monkeypatch, sample_environment, tmp_path +): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + input_path = tmp_path / "input.wav" + input_path.write_bytes(_wav_bytes(1)) + monkeypatch.setenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH", str(input_path)) + monkeypatch.setattr(sample, "SAVE_AUDIO", True) + monkeypatch.setattr(sample, "mkdtemp", MagicMock(side_effect=PermissionError("temporary directory unavailable"))) + + with pytest.raises(PermissionError, match="temporary directory unavailable"): + await sample.main() + + sample_environment.async_client.agents.create_version.assert_not_awaited() + sample_environment.async_client.agents.delete_version.assert_not_awaited() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("failure", [RuntimeError("offline receive failed"), asyncio.CancelledError()]) +async def test_async_sample_deletes_its_version_on_error_or_cancellation(monkeypatch, sample_environment, failure): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + with _recording() as recording: + monkeypatch.setattr(sample, "wave", SimpleNamespace(open=MagicMock(return_value=recording))) + sample_environment.async_connection.recv.side_effect = failure + with pytest.raises(type(failure)): + await sample.main() + + client = sample_environment.async_client + agent_name = client.agents.create_version.call_args.kwargs["agent_name"] + client.beta.voice_agents.live.connect.assert_called_once_with( + agent_name=agent_name, agent_version="owned-version", store=False + ) + client.agents.delete_version.assert_awaited_once_with(agent_name=agent_name, agent_version="owned-version") + client.agents.delete.assert_not_called() + sample_environment.async_connection.session.close.assert_awaited_once() + client.beta.voice_agents.live.connect.return_value.__aexit__.assert_awaited_once() + + +def _audio_sample_with_clock(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + clock = SimpleNamespace(now=0.0) + timer = SimpleNamespace(monotonic=lambda: clock.now) + monkeypatch.setattr(sample, "time", timer) + monkeypatch.setattr(sample_environment.helper, "time", timer) + return sample, clock + + +@pytest.mark.asyncio +@pytest.mark.parametrize("speech_level", [257, -257, 32767, -32768]) +@pytest.mark.parametrize("quiet_level", [0, 1, -1, 256, -256]) +async def test_audio_completion_ignores_continuous_quiet_pcm( + monkeypatch, sample_environment, speech_level, quiet_level +): + sample, clock = _audio_sample_with_clock(monkeypatch, sample_environment) + connection = sample_environment.async_connection + speech = speech_level.to_bytes(2, "little", signed=True) * 480 + quiet = quiet_level.to_bytes(2, "little", signed=True) * 480 + + async def receive(): + clock.now += 1 + pcm = speech if clock.now == 1 else quiet + return models.LiveOutputAudioDelta(delta=base64.b64encode(pcm).decode("ascii")) + + connection.recv.side_effect = receive + finished = asyncio.Event() + finished.set() + output_file = MagicMock() + + output = await sample._receive_audio(connection, finished, 10, output_file) + + assert clock.now == 4 + assert output.has_audio_activity + assert output.num_bytes == len(speech) + 3 * len(quiet) + assert output.chunks == 4 + assert b"".join(call.args[0] for call in output_file.writeframesraw.call_args_list) == speech + quiet * 3 + assert connection.recv.await_count == 4 + + +@pytest.mark.asyncio +@pytest.mark.parametrize("quiet_level", [0, 1, -1, 256, -256]) +async def test_audio_silence_only_cannot_be_a_successful_reply(monkeypatch, sample_environment, quiet_level): + sample, clock = _audio_sample_with_clock(monkeypatch, sample_environment) + connection = sample_environment.async_connection + quiet = quiet_level.to_bytes(2, "little", signed=True) * 480 + + async def receive(): + clock.now += 1 + if clock.now == 1: + return models.LiveOutputAudioDelta(delta=base64.b64encode(quiet).decode("ascii")) + raise asyncio.TimeoutError + + connection.recv.side_effect = receive + finished = asyncio.Event() + finished.set() + + with pytest.raises(TimeoutError, match="GPT Live reply audio"): + await sample._receive_audio(connection, finished, 10, None) + + assert clock.now == 10 + assert connection.recv.await_count == 10 + + +@pytest.mark.asyncio +async def test_continuous_reply_activity_does_not_extend_the_overall_audio_deadline(monkeypatch, sample_environment): + sample, clock = _audio_sample_with_clock(monkeypatch, sample_environment) + connection = sample_environment.async_connection + pcm = b"\x00\x08" * 480 + + async def receive(): + clock.now += 1 + return models.LiveOutputAudioDelta(delta=base64.b64encode(pcm).decode("ascii")) + + connection.recv.side_effect = receive + finished = asyncio.Event() + finished.set() + + with pytest.raises(TimeoutError, match="GPT Live reply audio"): + await sample._receive_audio(connection, finished, 10, None) + + assert clock.now == 10 + assert connection.recv.await_count == 10 + + +def _text_sample(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_text_conversation_async.py") + return sample, sample_environment.async_client, sample_environment.async_connection + + +@pytest.mark.asyncio +async def test_text_sample_reuses_one_session_and_waits_for_each_turn(monkeypatch, sample_environment, capsys): + sample, client, connection = _text_sample(monkeypatch, sample_environment) + prompts = ["My name is Ada.", "What is my name?"] + monkeypatch.setattr(sample, "TEXT_PROMPTS", prompts) + events = iter([_started(), *_text_response("Hello, Ada."), *_text_response("Your name is Ada."), _closed()]) + completed = 0 + submitted = [] + + def receive(*args, **kwargs): + nonlocal completed + event = next(events) + if event.get("type") == "response.event" and event["event"]["type"] == "response.completed": + completed += 1 + return event + + def submit(*, item): + assert completed == len(submitted) + submitted.append(item["content"][0]["text"]) + + connection.recv.side_effect = receive + connection.response.item.create.side_effect = submit + + await sample.main() + + assert submitted == prompts + assert completed == 2 + assert connection.response.create.call_count == 2 + assert connection.session.close.call_count == 1 + client.beta.voice_agents.live.connect.assert_called_once() + client.agents.create_version.assert_awaited_once() + client.agents.delete_version.assert_awaited_once() + client.agents.delete.assert_not_called() + connection.session.start.assert_not_called() + connection.response.cancel.assert_not_called() + client.beta.voice_agents.live.connect.return_value.__aexit__.assert_awaited_once() + output = capsys.readouterr().out + assert output.count("Responses backend: Hello, Ada.\n") == 1 + assert output.count("Responses backend: Your name is Ada.\n") == 1 + + +@pytest.mark.asyncio +async def test_text_sample_keeps_the_original_single_prompt_default(monkeypatch, sample_environment): + sample, client, connection = _text_sample(monkeypatch, sample_environment) + connection.recv.side_effect = [_started(), *_text_response("Seattle has a rainy climate."), _closed()] + + await sample.main() + + definition = client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition.delegation, models.VoiceAgentLiveResponsesDelegation) + assert definition.delegation.responses.model == "backend-deployment-test" + connection.response.item.create.assert_awaited_once_with( + item={ + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": "Why is Seattle known for rain? Answer in one short sentence."}], + } + ) + connection.response.create.assert_awaited_once() + + +@pytest.mark.parametrize("prompts", [[], [""], ["first", " "], "not-a-prompt-list"]) +@pytest.mark.asyncio +async def test_text_sample_rejects_empty_or_invalid_scripted_prompts(monkeypatch, sample_environment, prompts): + sample, client, _ = _text_sample(monkeypatch, sample_environment) + monkeypatch.setattr(sample, "TEXT_PROMPTS", prompts) + + with pytest.raises(ValueError, match="prompt"): + await sample.main() + + client.agents.create_version.assert_not_called() + client.beta.voice_agents.live.connect.assert_not_called() + client.agents.delete_version.assert_not_called() + + +@pytest.mark.asyncio +async def test_text_sample_stops_on_a_later_backend_failure_and_cleans_up(monkeypatch, sample_environment): + sample, client, connection = _text_sample(monkeypatch, sample_environment) + monkeypatch.setattr(sample, "TEXT_PROMPTS", ["first", "second", "must not be sent"]) + connection.recv.side_effect = [ + _started(), + *_text_response("First answer."), + _response("response.failed", response={"error": {"message": "backend failed"}}), + ] + + with pytest.raises(RuntimeError, match="Responses backend response.failed"): + await sample.main() + + assert connection.response.item.create.call_count == 2 + assert connection.response.create.call_count == 2 + connection.session.close.assert_awaited_once() + agent_name = client.agents.create_version.call_args.kwargs["agent_name"] + client.agents.delete_version.assert_awaited_once_with(agent_name=agent_name, agent_version="owned-version") + + +@pytest.mark.parametrize("empty", [True, False], ids=["empty-text", "unexpected-tool"]) +@pytest.mark.asyncio +async def test_text_sample_rejects_non_text_backend_completions(monkeypatch, sample_environment, empty): + sample, client, connection = _text_sample(monkeypatch, sample_environment) + monkeypatch.setattr(sample, "TEXT_PROMPTS", ["one", "must not be sent"]) + events = [_started()] + if not empty: + events.append( + _response( + "response.output_item.done", + item={"type": "function_call", "call_id": "unexpected-call", "name": "unexpected", "arguments": "{}"}, + ) + ) + events.append(_response("response.completed", response={"status": "completed", "output": []})) + connection.recv.side_effect = events + + with pytest.raises(RuntimeError, match="without returning any output text|unexpectedly requested"): + await sample.main() + + connection.response.item.create.assert_awaited_once() + client.agents.delete_version.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_async_audio_create_failure_does_not_delete_an_existing_version(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + client = sample_environment.async_client + client.agents.create_version.side_effect = RuntimeError("create failed") + + with _recording() as recording: + monkeypatch.setattr(sample, "wave", SimpleNamespace(open=MagicMock(return_value=recording))) + with pytest.raises(RuntimeError, match="create failed"): + await sample.main() + + client.agents.delete_version.assert_not_awaited() + client.beta.voice_agents.live.connect.assert_not_called() + + +@pytest.mark.asyncio +async def test_async_response_collection_keeps_canonical_tool_ids_and_granular_text(sample_environment): + connection = sample_environment.async_connection + call = { + "type": "function_call", + "call_id": "canonical-call", + "name": "get_weather", + "arguments": '{"city":"Seattle"}', + } + connection.recv.side_effect = [ + _response("response.output_text.delta", item_id="message-test", content_index=0, delta="Partial"), + _response("response.output_text.done", item_id="message-test", content_index=0, text="Complete text"), + _response("response.function_call_arguments.done", item_id="different-item-id", arguments='{"city":"Seattle"}'), + _response("response.output_item.done", item=call), + _response("response.completed", response={"status": "completed", "output": []}), + ] + + text, calls = await sample_environment.helper.receive_response_async(connection) + + assert text == "Complete text" + assert calls == [call] + + +@pytest.mark.asyncio +async def test_async_response_collection_does_not_extend_its_deadline(monkeypatch, sample_environment): + helper = sample_environment.helper + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=MagicMock(side_effect=[0, 1, 61]))) + sample_environment.async_connection.recv.return_value = {"type": "future.event"} + + with pytest.raises(TimeoutError, match="Responses backend to complete"): + await helper.receive_response_async(sample_environment.async_connection) + + sample_environment.async_connection.recv.assert_awaited_once() + assert sample_environment.async_connection.recv.call_count == 1 + + +@pytest.mark.asyncio +async def test_async_lifecycle_expired_deadline_does_not_create_an_unawaited_receive(monkeypatch, sample_environment): + helper = sample_environment.helper + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=MagicMock(side_effect=[0, 1, 61]))) + sample_environment.async_connection.recv.return_value = {"type": "future.event"} + + with pytest.raises(TimeoutError, match="session.started"): + await helper.wait_for_event_async(sample_environment.async_connection, "session.started") + + sample_environment.async_connection.recv.assert_awaited_once() + assert sample_environment.async_connection.recv.call_count == 1 + + +@pytest.mark.asyncio +async def test_async_close_expired_deadline_does_not_create_an_unawaited_send(monkeypatch, sample_environment): + helper = sample_environment.helper + monkeypatch.setattr(helper, "time", SimpleNamespace(monotonic=MagicMock(side_effect=[0, 11]))) + + with pytest.raises(TimeoutError, match="closing the GPT Live session"): + await helper.close_session_async(sample_environment.async_connection) + + sample_environment.async_connection.session.close.assert_not_called() + + +def _wav_bytes(channels): + stream = io.BytesIO() + with wave.open(stream, "wb") as writer: + writer.setparams((channels, 2, 24000, 0, "NONE", "not compressed")) + writer.writeframes(b"\x01\x02" * 1200 * channels) + return stream.getvalue() + + +@pytest.fixture +def rest_sample(monkeypatch, sample_environment, tmp_path): + sample = _load_module(monkeypatch, "sample_voice_agent_live_read_conversation.py") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_NAME", "stored-agent-test") + monkeypatch.setenv("FOUNDRY_VOICE_CONVERSATION_ID", "conversation-test") + client = sample_environment.client + operations = client.beta.voice_agents.live_conversations + conversation = models.VoiceAgentLiveConversation( + {"id": "conversation-test", "status": "completed", "created_at": 1, "completed_at": 2} + ) + audio = models.VoiceAudioItem( + { + "conversation_id": "conversation-test", + "item_id": "speech-test", + "role": "agent", + "format": "wav", + "codec": "pcm16", + "sample_rate": 24000, + "channels": 1, + "duration_ms": 50, + } + ) + speech = models.VoiceAgentLiveOutputConversationItem( + {"id": "speech-test", "transcription": "A synthetic transcript.", "audio": audio.as_dict()} + ) + delegation = models.VoiceAgentLiveClientDelegationConversationItem( + {"id": "delegation-test", "created_at": 1, "commentary": "Synthetic application guidance."} + ) + items = [speech, delegation] + recording = models.VoiceRecording( + { + "conversation_id": "conversation-test", + "format": "wav", + "sample_rate": 24000, + "channels": 2, + "channel_layout": {"left": "user", "right": "agent"}, + "duration_ms": 50, + } + ) + item_bytes, merged_bytes = _wav_bytes(1), _wav_bytes(2) + operations.get = MagicMock(return_value=conversation) + operations.list = MagicMock(side_effect=lambda *args, **kwargs: iter([conversation])) + operations.list_items = MagicMock(side_effect=lambda *args, **kwargs: iter(items)) + operations.get_item = MagicMock( + side_effect=lambda agent, conversation, item: next(v for v in items if v.id == item) + ) + operations.get_audio_item = MagicMock(return_value=audio) + operations.get_audio = MagicMock(return_value=recording) + operations.download_audio_item = MagicMock(side_effect=lambda *args: iter([item_bytes[:12], item_bytes[12:]])) + operations.download_audio = MagicMock(side_effect=lambda *args: iter([merged_bytes[:12], merged_bytes[12:]])) + operations.delete = MagicMock() + output_factory, directories = _capture_sample_output_directories(monkeypatch, sample, tmp_path) + + return SimpleNamespace( + sample=sample, + client=client, + operations=operations, + conversation=conversation, + audio=audio, + recording=recording, + items=items, + run=sample.main, + item_bytes=item_bytes, + merged_bytes=merged_bytes, + output_factory=output_factory, + directories=directories, + ) + + +@pytest.mark.parametrize("read_fails", [False, True], ids=["success", "read-failure"]) +def test_live_rest_sample_cleans_up_its_own_conversation(rest_sample, sample_environment, monkeypatch, read_fails): + monkeypatch.delenv("FOUNDRY_VOICE_CONVERSATION_ID") + monkeypatch.setattr(rest_sample.sample, "_receive_greeting", MagicMock()) + monkeypatch.setattr(rest_sample.sample, "_wait_for_recording", MagicMock()) + started = _started() + started.conversation_id = rest_sample.conversation.id + sample_environment.connection.recv.side_effect = [started, _closed()] + if read_fails: + rest_sample.operations.download_audio.side_effect = RuntimeError("REST read failed") + with pytest.raises(RuntimeError, match="REST read failed"): + rest_sample.run() + else: + rest_sample.run() + + rest_sample.client.agents.create_version.assert_called_once() + agent_name = rest_sample.client.agents.create_version.call_args.kwargs["agent_name"] + assert agent_name != "stored-agent-test" + rest_sample.operations.get.assert_called_once_with(agent_name, "conversation-test") + rest_sample.operations.delete.assert_called_once_with(agent_name, "conversation-test") + rest_sample.client.agents.delete_version.assert_called_once_with( + agent_name=agent_name, agent_version="owned-version" + ) + rest_sample.client.agents.delete.assert_not_called() + + +def test_live_rest_sample_downloads_to_user_temp_without_modifying_resources( + rest_sample, tmp_path, capsys, monkeypatch +): + for variable in ("FOUNDRY_VOICE_AGENT_MODEL", "FOUNDRY_MODEL_NAME", "FOUNDRY_VOICE_AUDIO_INPUT_PATH"): + monkeypatch.delenv(variable, raising=False) + rest_sample.run() + + operations = rest_sample.operations + operations.get.assert_called_once_with("stored-agent-test", "conversation-test") + operations.list.assert_called_once_with("stored-agent-test", limit=5, order="desc") + operations.list_items.assert_called_once_with("stored-agent-test", "conversation-test", limit=20, order="asc") + assert operations.get_item.call_count == 2 + operations.get_audio_item.assert_called_once_with("stored-agent-test", "conversation-test", "speech-test") + operations.get_audio.assert_called_once_with("stored-agent-test", "conversation-test") + operations.download_audio.assert_called_once_with("stored-agent-test", "conversation-test") + operations.download_audio_item.assert_called_once_with("stored-agent-test", "conversation-test", "speech-test") + operations.delete.assert_not_called() + assert not rest_sample.client.agents.mock_calls + rest_sample.client.beta.voice_agents.live.connect.assert_not_called() + rest_sample.client.beta.voice_agents.conversations.get.assert_not_called() + rest_sample.output_factory.assert_called_once_with(prefix="voice-agent-live-") + output_directory = rest_sample.directories[0] + assert output_directory.parent == tmp_path + assert (output_directory / "item-0001.wav").read_bytes() == rest_sample.item_bytes + assert (output_directory / "conversation.wav").read_bytes() == rest_sample.merged_bytes + output = capsys.readouterr().out + assert str(output_directory) in output + assert "A synthetic transcript." in output + assert "Non-speech item" in output + assert "Read-only REST run" in output + rest_sample.client.__exit__.assert_called_once() + + +def test_live_rest_sample_uses_unique_persistent_output_folders(rest_sample): + rest_sample.run() + first = rest_sample.directories[0] + rest_sample.run() + second = rest_sample.directories[1] + + assert first != second + assert rest_sample.output_factory.call_count == 2 + for directory in (first, second): + assert (directory / "conversation.wav").read_bytes() == rest_sample.merged_bytes + assert (directory / "item-0001.wav").read_bytes() == rest_sample.item_bytes + rest_sample.operations.delete.assert_not_called() + + +@pytest.mark.parametrize("status", [404, 409, 500]) +def test_live_rest_sample_surfaces_service_failures_without_fallback_or_deletion(rest_sample, status, capsys): + failure = HttpResponseError("service failure") + failure.status_code = status + rest_sample.operations.get.side_effect = failure + + with pytest.raises(HttpResponseError) as caught: + rest_sample.run() + + assert caught.value is failure + rest_sample.operations.delete.assert_not_called() + assert not rest_sample.client.beta.voice_agents.conversations.mock_calls + assert f"HTTP {status}" in capsys.readouterr().out + rest_sample.output_factory.assert_not_called() + rest_sample.client.__exit__.assert_called_once() + + +@pytest.mark.parametrize("status", ["in_progress", "failed"]) +def test_live_rest_sample_requires_successful_session_finalization(rest_sample, status): + rest_sample.conversation.status = status + + with pytest.raises(RuntimeError, match="must finish successfully"): + rest_sample.run() + + rest_sample.operations.list_items.assert_not_called() + rest_sample.operations.download_audio.assert_not_called() + rest_sample.operations.delete.assert_not_called() + rest_sample.output_factory.assert_not_called() + + +@pytest.mark.parametrize( + "method,filename", + [ + ("download_audio_item", "item-0001.wav"), + ("download_audio", "conversation.wav"), + ], +) +@pytest.mark.parametrize("empty", [True, False], ids=["empty-stream", "failed-stream"]) +def test_live_rest_download_failures_remove_incomplete_files_without_deleting_resources( + rest_sample, method, filename, empty +): + def sync_chunks(): + if not empty: + yield b"partial" + raise ConnectionError("stream failed") + + getattr(rest_sample.operations, method).side_effect = lambda *args: sync_chunks() + + with pytest.raises(RuntimeError if empty else ConnectionError, match="no bytes|stream failed"): + rest_sample.run() + + assert not (rest_sample.directories[0] / filename).exists() + rest_sample.operations.delete.assert_not_called() + + +@pytest.mark.parametrize( + "filename,method", + [ + ("item-0001.wav", "download_audio_item"), + ("conversation.wav", "download_audio"), + ], +) +def test_live_rest_sample_never_overwrites_an_existing_recording(rest_sample, tmp_path, filename, method): + path = tmp_path / filename + path.write_bytes(b"keep existing audio") + rest_sample.output_factory.side_effect = lambda **kwargs: str(tmp_path) + + with pytest.raises(FileExistsError): + rest_sample.run() + + assert path.read_bytes() == b"keep existing audio" + getattr(rest_sample.operations, method).assert_not_called() + rest_sample.operations.delete.assert_not_called() + + +@pytest.mark.parametrize("level", ["item", "merged"]) +def test_live_rest_sample_explains_byos_without_proxying_downloads(rest_sample, capsys, level): + metadata = rest_sample.audio if level == "item" else rest_sample.recording + metadata.blob_uri = "https://example.invalid/private-recording" + with pytest.raises(RuntimeError, match="not BYOS audio"): + rest_sample.run() + method = "download_audio_item" if level == "item" else "download_audio" + getattr(rest_sample.operations, method).assert_not_called() + rest_sample.operations.delete.assert_not_called() + output = capsys.readouterr().out + assert "BYOS" in output and "https://example.invalid/private-recording" not in output + + +def test_live_rest_sample_rejects_repeated_paging_items(rest_sample): + rest_sample.items.append(rest_sample.items[0]) + + with pytest.raises(RuntimeError, match="pager repeated an item"): + rest_sample.run() + + rest_sample.operations.delete.assert_not_called() + + +def test_live_rest_sample_temp_directory_failure_leaves_service_resources_untouched(rest_sample): + rest_sample.output_factory.side_effect = PermissionError("temporary directory unavailable") + + with pytest.raises(PermissionError, match="temporary directory unavailable"): + rest_sample.run() + + rest_sample.operations.list_items.assert_not_called() + rest_sample.operations.download_audio.assert_not_called() + rest_sample.operations.delete.assert_not_called() + rest_sample.client.__exit__.assert_called_once() + + +@pytest.mark.parametrize("agent_name", [None, "", " "], ids=["unset", "empty", "blank"]) +def test_live_rest_sample_requires_an_agent_name_for_an_existing_conversation(rest_sample, monkeypatch, agent_name): + if agent_name is None: + monkeypatch.delenv("FOUNDRY_VOICE_AGENT_NAME") + else: + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_NAME", agent_name) + + with pytest.raises(ValueError, match="nonblank"): + rest_sample.run() + + rest_sample.operations.get.assert_not_called() + rest_sample.operations.delete.assert_not_called() + rest_sample.output_factory.assert_not_called() + + +@pytest.fixture +def microphone_sample(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + monkeypatch.setattr(sample, "USE_MICROPHONE", True) + speaker = MagicMock() + microphone = MagicMock() + engine = MagicMock() + engine.open.side_effect = [speaker, microphone] + backend = SimpleNamespace(PyAudio=MagicMock(return_value=engine), paInt16=8, paContinue=0, paAbort=2) + monkeypatch.setattr(sample, "_microphone_backend", lambda: backend) + return SimpleNamespace( + sample=sample, + connection=sample_environment.async_connection, + client=sample_environment.async_client, + backend=backend, + engine=engine, + speaker=speaker, + microphone=microphone, + make=lambda: sample._MicrophoneAudio(sample_environment.async_connection, backend), + ) + + +@pytest.mark.asyncio +async def test_microphone_mode_does_not_require_a_wav_and_preserves_live_lifecycle( + monkeypatch, microphone_sample, capsys +): + setup = microphone_sample + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH") + setup.connection.recv.side_effect = [_started(), _closed()] + + await setup.sample.main() + + assert setup.engine.open.call_count == 2 + output_options, input_options = [call.kwargs for call in setup.engine.open.call_args_list] + assert output_options["output"] is True and input_options["input"] is True + for options in (output_options, input_options): + assert options["format"] == setup.backend.paInt16 + assert options["rate"] == 24000 and options["channels"] == 1 + assert options["frames_per_buffer"] == 1200 and options["start"] is False + setup.speaker.start_stream.assert_called_once() + setup.microphone.start_stream.assert_called_once() + setup.speaker.close.assert_called_once() + setup.microphone.close.assert_called_once() + setup.engine.terminate.assert_called_once() + definition = setup.client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition, models.VoiceAgentLiveDefinition) and definition.store is False + setup.client.agents.delete_version.assert_awaited_once() + setup.connection.session.start.assert_not_called() + setup.connection.response.cancel.assert_not_called() + setup.client.beta.voice_agents.realtime.connect.assert_not_called() + assert "Speak now" in capsys.readouterr().out + + +@pytest.mark.asyncio +async def test_microphone_dependency_error_precedes_agent_creation(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + monkeypatch.setitem(sys.modules, "pyaudio", None) + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH") + monkeypatch.setattr(sample, "USE_MICROPHONE", True) + + with pytest.raises(RuntimeError, match="pip install pyaudio"): + await sample.main() + + sample_environment.async_client.agents.create_version.assert_not_awaited() + + +@pytest.mark.asyncio +async def test_microphone_counts_only_successfully_sent_pcm(microphone_sample): + audio = microphone_sample.make() + pcm = b"\x01\x02" * 1200 + await audio._append_input_audio(pcm) + assert audio.input_bytes == len(pcm) + microphone_sample.connection.session.input_audio.append.assert_awaited_once_with(audio=pcm) + microphone_sample.connection.session.input_audio.append.side_effect = ConnectionError("send failed") + with pytest.raises(ConnectionError, match="send failed"): + await audio._append_input_audio(pcm) + assert audio.input_bytes == len(pcm) + await audio.stop() + + +@pytest.mark.asyncio +async def test_microphone_callback_sends_raw_pcm_on_the_event_loop(microphone_sample): + audio = microphone_sample.make() + audio.start() + pcm = b"\x01\x02" * 1200 + + assert audio._capture_callback(pcm, 1200, None, 0) == (None, microphone_sample.backend.paContinue) + await asyncio.wrap_future(audio._pending_send) + + assert audio.input_bytes == len(pcm) + microphone_sample.connection.session.input_audio.append.assert_awaited_once_with(audio=pcm) + await audio.stop() + + +@pytest.mark.asyncio +async def test_microphone_capture_backpressure_drops_a_frame_without_creating_more_sends(microphone_sample): + audio = microphone_sample.make() + audio.start() + pending = Future() + audio._pending_send = pending + + assert audio._capture_callback(b"\x01\x02" * 1200, 1200, None, 0) == (None, microphone_sample.backend.paContinue) + assert audio._pending_send is pending and audio.dropped_frames == 1 + microphone_sample.connection.session.input_audio.append.assert_not_called() + pending.set_result(None) + await audio.stop() + + +@pytest.mark.asyncio +async def test_microphone_callback_send_failure_is_raised_by_the_receiver(microphone_sample): + audio = microphone_sample.make() + audio.start() + failure = ConnectionError("captured audio send failed") + pending = Future() + pending.set_exception(failure) + audio._pending_send = pending + + assert audio._capture_callback(b"\x00\x00" * 1200, 1200, None, 0) == (None, microphone_sample.backend.paAbort) + with pytest.raises(ConnectionError) as caught: + audio.check_capture_error() + assert caught.value is failure + with pytest.raises(ConnectionError): + await audio.stop() + microphone_sample.speaker.close.assert_called_once() + microphone_sample.microphone.close.assert_called_once() + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_shutdown_waits_for_the_last_send_and_closes_once(microphone_sample): + audio = microphone_sample.make() + audio.start() + pending = Future() + audio._pending_send = pending + shutdown = asyncio.create_task(audio.stop()) + await asyncio.sleep(0) + assert not shutdown.done() + microphone_sample.microphone.close.assert_called_once() + pending.set_result(None) + await shutdown + await audio.stop() + assert audio._pending_send is None + microphone_sample.microphone.close.assert_called_once() + microphone_sample.speaker.close.assert_called_once() + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_playback_preserves_remainder_and_pads_exact_callback_frames(microphone_sample): + audio = microphone_sample.make() + audio.start() + audio.enqueue_audio(b"\x01\x02" * 5) + + first, state = audio._playback_callback(None, 3, None, 0) + second, _ = audio._playback_callback(None, 4, None, 0) + + assert first == b"\x01\x02" * 3 + assert second == b"\x01\x02" * 2 + b"\x00" * 4 + assert state == microphone_sample.backend.paContinue + assert audio.output_bytes == 10 + await audio.stop() + + +@pytest.mark.asyncio +async def test_microphone_rejects_partial_pcm_and_reports_playback_backpressure(microphone_sample): + audio = microphone_sample.make() + audio._playback_queue = queue.Queue(maxsize=1) + with pytest.raises(ValueError, match="PCM16"): + audio.enqueue_audio(b"\x01") + assert audio.output_bytes == 0 + audio.enqueue_audio(b"\x01\x02") + with pytest.raises(RuntimeError, match="playback"): + audio.enqueue_audio(b"\x03\x04") + assert audio.output_bytes == 4 + await audio.stop() + + +@pytest.mark.asyncio +async def test_microphone_input_device_failure_releases_the_opened_speaker(microphone_sample): + microphone_sample.engine.open.side_effect = [microphone_sample.speaker, OSError("microphone unavailable")] + with pytest.raises(OSError, match="microphone unavailable"): + await microphone_sample.sample._stream_microphone(microphone_sample.connection, microphone_sample.backend, None) + microphone_sample.speaker.close.assert_called_once() + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_receives_audio_and_transcripts_and_saves_only_explicit_reply_output( + microphone_sample, capsys +): + pcm = b"\x01\x02" * 1200 + microphone_sample.connection.recv.side_effect = [ + models.LiveServerEventLiveInputTranscriptDelta(delta="Hello"), + models.LiveServerEventLiveOutputTranscriptDelta(delta="Hi"), + models.LiveOutputAudioDelta(delta=base64.b64encode(pcm).decode("ascii")), + _closed(), + ] + output_file = MagicMock() + + closed = await microphone_sample.sample._stream_microphone( + microphone_sample.connection, microphone_sample.backend, output_file + ) + + assert closed is True + output_file.writeframesraw.assert_called_once_with(pcm) + text = capsys.readouterr().out + assert "You: Hello" in text and "Agent: Hi" in text + assert f"{len(pcm)} bytes" in text + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_cancellation_closes_the_session_and_deletes_only_its_version(microphone_sample, monkeypatch): + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH") + microphone_sample.connection.recv.side_effect = [_started(), asyncio.CancelledError(), _closed()] + + with pytest.raises(asyncio.CancelledError): + await microphone_sample.sample.main() + + microphone_sample.connection.session.close.assert_awaited_once() + microphone_sample.client.agents.delete_version.assert_awaited_once() + microphone_sample.client.agents.delete.assert_not_called() + microphone_sample.microphone.close.assert_called_once() + microphone_sample.speaker.close.assert_called_once() + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_service_errors_are_not_silently_successful(microphone_sample, monkeypatch): + monkeypatch.delenv("FOUNDRY_VOICE_AUDIO_INPUT_PATH") + microphone_sample.connection.recv.side_effect = [ + _started(), + {"type": "error", "error": {"code": "offline_error", "message": "service failed"}}, + ] + with pytest.raises(RuntimeError, match="service failed"): + await microphone_sample.sample.main() + microphone_sample.client.agents.delete_version.assert_awaited_once() + microphone_sample.microphone.close.assert_called_once() + microphone_sample.speaker.close.assert_called_once() + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_stopped_capture_does_not_schedule_an_audio_send(microphone_sample): + audio = microphone_sample.make() + assert audio._capture_callback(b"\x00\x00" * 1200, 1200, None, 0) == (None, microphone_sample.backend.paAbort) + microphone_sample.connection.session.input_audio.append.assert_not_called() + await audio.stop() + + +@pytest.mark.asyncio +async def test_cancelled_microphone_send_is_an_error_not_a_successful_user_stop(microphone_sample): + audio = microphone_sample.make() + audio.start() + pending = Future() + pending.cancel() + audio._pending_send = pending + assert audio._capture_callback(b"\x00\x00" * 1200, 1200, None, 0) == (None, microphone_sample.backend.paAbort) + with pytest.raises(RuntimeError, match="send was cancelled"): + audio.check_capture_error() + with pytest.raises(RuntimeError, match="send was cancelled"): + await audio.stop() + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("device,status", [("microphone", 2), ("speaker", 4)]) +async def test_microphone_device_status_errors_are_reported_to_the_receiver(microphone_sample, device, status): + audio = microphone_sample.make() + audio.start() + if device == "microphone": + result, state = audio._capture_callback(b"\x00\x00" * 1200, 1200, None, status) + assert result is None + else: + result, state = audio._playback_callback(None, 1200, None, status) + assert len(result) == 2400 + assert state == microphone_sample.backend.paAbort + with pytest.raises(RuntimeError, match="callback reported audio status"): + audio.check_capture_error() + await audio.stop() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("reason", ["connection_lost", "content"]) +async def test_microphone_abnormal_session_termination_is_not_a_normal_completion(microphone_sample, reason): + closed = _closed() + closed.reason = reason + microphone_sample.connection.recv.return_value = closed + with pytest.raises(RuntimeError, match="ended unexpectedly"): + await microphone_sample.sample._stream_microphone(microphone_sample.connection, microphone_sample.backend, None) + microphone_sample.engine.terminate.assert_called_once() + + +@pytest.mark.asyncio +async def test_microphone_client_delegation_uses_associated_live_commentary(microphone_sample): + microphone_sample.connection.recv.side_effect = [ + models.LiveServerEventLiveDelegationCreated( + {"delegation": {"id": "delegation-test", "target": "client", "created_at": 1}} + ), + _closed(), + ] + await microphone_sample.sample._stream_microphone(microphone_sample.connection, microphone_sample.backend, None) + microphone_sample.connection.session.commentary.append.assert_awaited_once_with( + content="This sample cannot look up external information. Briefly acknowledge the spoken request.", + delegation_id="delegation-test", + ) + microphone_sample.connection.response.cancel.assert_not_called() + + +@pytest.mark.asyncio +async def test_wav_mode_does_not_import_or_initialize_optional_microphone_devices(monkeypatch, sample_environment): + sample = _load_module(monkeypatch, "sample_voice_agent_live_audio_conversation_async.py") + monkeypatch.setitem(sys.modules, "pyaudio", None) + microphone_backend = MagicMock(side_effect=AssertionError("WAV mode initialized a microphone backend")) + monkeypatch.setattr(sample, "_microphone_backend", microphone_backend) + monkeypatch.setattr(sample, "_stream_recording", AsyncMock()) + sample_environment.async_connection.recv.side_effect = [_started(), _closed()] + with _recording() as recording: + monkeypatch.setattr(sample, "wave", SimpleNamespace(open=MagicMock(return_value=recording))) + await sample.main() + microphone_backend.assert_not_called() + sample._stream_recording.assert_awaited_once() + sample_environment.async_client.agents.delete_version.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_microphone_cannot_restart_devices_after_shutdown(microphone_sample): + audio = microphone_sample.make() + await audio.stop() + with pytest.raises(RuntimeError, match="Cannot restart closed"): + audio.start() + microphone_sample.engine.open.assert_not_called() + + +@pytest.mark.asyncio +async def test_microphone_stop_failure_still_drains_the_last_send_and_releases_every_device(microphone_sample): + audio = microphone_sample.make() + audio.start() + pending = Future() + pending.set_result(None) + audio._pending_send = pending + microphone_sample.microphone.stop_stream.side_effect = OSError("device stop failed") + with pytest.raises(OSError, match="device stop failed"): + await audio.stop() + assert audio._pending_send is None + microphone_sample.microphone.close.assert_called_once() + microphone_sample.speaker.close.assert_called_once() + microphone_sample.engine.terminate.assert_called_once() diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_realtime_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_realtime_samples.py new file mode 100644 index 000000000000..573eb8e85965 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/samples/test_realtime_samples.py @@ -0,0 +1,607 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline execution of the Realtime text and local function-tool sample entrypoints.""" + +import asyncio +import base64 +from collections import deque +import importlib.util +import json +from pathlib import Path +import sys +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock, call + +import pytest + +from azure.ai.projects import models +from azure.ai.projects.operations import BetaRealtimeConnection + +pytestmark = pytest.mark.asyncio +_SAMPLE_DIRECTORY = Path(__file__).resolve().parents[2].joinpath("samples", "agents", "voice") +_ENDPOINT = "https://example.invalid/api/projects/offline" +_AGENT_NAME = "realtime-offline" +_OWNED_VERSION = "owned-realtime-version" +_CONVERSATION_ID = "conversation-offline" +_TEXT_SAMPLES = ("sample_voice_agent_realtime_text_conversation_async.py",) +_TOOL_SAMPLE = "sample_voice_agent_realtime_function_tool_async.py" + + +def _load_sample(monkeypatch, filename): + name = f"offline_{Path(filename).stem}" + spec = importlib.util.spec_from_file_location(name, _SAMPLE_DIRECTORY.joinpath(filename)) + assert spec is not None and spec.loader is not None + sample = importlib.util.module_from_spec(spec) + monkeypatch.setitem(sys.modules, name, sample) + spec.loader.exec_module(sample) + return sample + + +def _session_created(): + return models.RealtimeServerEventSessionCreated( + { + "event_id": "session-created", + "session": {"id": "session-offline", "type": "realtime"}, + "conversation_id": _CONVERSATION_ID, + } + ) + + +def _response_created(response_id): + return models.RealtimeServerEventResponseCreated( + {"event_id": f"created-{response_id}", "response": {"id": response_id, "status": "in_progress"}} + ) + + +def _response_done(response_id, *, status="completed", output=None): + return models.RealtimeServerEventResponseDone( + { + "event_id": f"done-{response_id}", + "response": {"id": response_id, "status": status, "output": output or []}, + } + ) + + +def _transcript_done(response_id, transcript): + return models.RealtimeServerEventResponseAudioTranscriptDone( + { + "event_id": f"transcript-{response_id}", + "response_id": response_id, + "item_id": f"item-{response_id}", + "output_index": 0, + "content_index": 0, + "transcript": transcript, + } + ) + + +def _error(): + return models.RealtimeServerEventError( + { + "type": "error", + "event_id": "error-offline", + "error": {"type": "invalid_request_error", "message": "offline command rejected"}, + } + ) + + +def _function_arguments(*, call_id="canonical-call-test", name="get_weather", arguments='{"city":"Seattle"}'): + return models.RealtimeServerEventResponseFunctionCallArgumentsDone( + { + "event_id": f"arguments-{call_id}", + "response_id": "tool-response", + "item_id": f"item-{call_id}", + "output_index": 0, + "call_id": call_id, + "name": name, + "arguments": arguments, + } + ) + + +@pytest.fixture(params=["ga", "legacy"], ids=["ga-output-events", "legacy-output-events"]) +def realtime_output_event(request): + event_types = { + "audio.delta": ( + "response.output_audio.delta", + "response.audio.delta", + models.RealtimeServerEventResponseAudioDelta, + ), + "audio.done": ( + "response.output_audio.done", + "response.audio.done", + models.RealtimeServerEventResponseAudioDone, + ), + "audio_transcript.delta": ( + "response.output_audio_transcript.delta", + "response.audio_transcript.delta", + models.RealtimeServerEventResponseAudioTranscriptDelta, + ), + "audio_transcript.done": ( + "response.output_audio_transcript.done", + "response.audio_transcript.done", + models.RealtimeServerEventResponseAudioTranscriptDone, + ), + "text.delta": ( + "response.output_text.delta", + "response.text.delta", + models.RealtimeServerEventResponseTextDelta, + ), + "text.done": ( + "response.output_text.done", + "response.text.done", + models.RealtimeServerEventResponseTextDone, + ), + } + + def parse(kind, response_id, **fields): + ga_type, legacy_type, event_model = event_types[kind] + event_type = ga_type if request.param == "ga" else legacy_type + if kind == "audio.delta": + fields["delta"] = base64.b64encode(fields["delta"]).decode("ascii") + payload = { + "type": event_type, + "event_id": f"{kind}-{response_id}", + "response_id": response_id, + "item_id": f"item-{response_id}", + "output_index": 0, + "content_index": 0, + **fields, + } + transport = MagicMock() + transport.recv.return_value = json.dumps(payload) + with BetaRealtimeConnection(transport) as connection: + event = connection.recv() + if request.param == "ga": + assert type(event) is event_model + assert event.as_dict() == payload + else: + assert type(event) is dict + assert event == payload + assert event["type"] == event_type + return event + + return parse + + +class _SampleHarness: + """Provide strict scripted receives and record sends without replacing the sample loops.""" + + def __init__(self, monkeypatch, filename): + self.is_async = filename.endswith("_async.py") + self.is_text = filename in _TEXT_SAMPLES + self.events = deque() + self.prompts = deque() + self.actions = [] + self.players = [] + self.client = MagicMock() + self.credential = MagicMock() + self.connection = MagicMock() + self.manager = self.client.beta.voice_agents.realtime.connect.return_value + mock_type = AsyncMock if self.is_async else MagicMock + + for resource in (self.client, self.credential): + getattr(resource, "__aenter__" if self.is_async else "__enter__").return_value = resource + getattr(resource, "__aexit__" if self.is_async else "__exit__").return_value = False + getattr(self.manager, "__aenter__" if self.is_async else "__enter__").return_value = self.connection + getattr(self.manager, "__aexit__" if self.is_async else "__exit__").return_value = False + + self.client.agents.create_version = mock_type(return_value=SimpleNamespace(version=_OWNED_VERSION)) + self.client.agents.delete_version = mock_type() + self.connection.recv = mock_type(side_effect=self._receive) + self.connection.conversation.item.create = mock_type(side_effect=self._create_item) + self.connection.response.create = mock_type(side_effect=self._create_response) + self.connection.response.cancel = mock_type(side_effect=self._cancel_response) + if self.is_async: + self.connection.__aiter__.side_effect = self._iterate + + self.conversations = self.client.beta.voice_agents.conversations + self.conversations.get = mock_type( + return_value=SimpleNamespace(id=_CONVERSATION_ID, status="completed", created_at=0) + ) + persisted_items = [ + {"id": "stored-user", "role": "user", "content": [{"text": "Stored user turn."}]}, + {"id": "stored-agent", "role": "assistant", "content": [{"transcript": "Stored assistant turn."}]}, + ] + if self.is_async: + page = MagicMock() + page.__aiter__.return_value = persisted_items + self.conversations.list_items.return_value = page + else: + self.conversations.list_items.return_value = persisted_items + + monkeypatch.setenv("FOUNDRY_PROJECT_ENDPOINT", _ENDPOINT) + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_MODEL", "realtime-deployment-offline") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_NAME", _AGENT_NAME) + monkeypatch.setattr("dotenv.load_dotenv", lambda: False) + monkeypatch.setitem(sys.modules, "pyaudio", None) + self.client_factory = MagicMock(return_value=self.client) + self.credential_factory = MagicMock(return_value=self.credential) + namespace = "azure.ai.projects.aio" if self.is_async else "azure.ai.projects" + identity_namespace = "azure.identity.aio" if self.is_async else "azure.identity" + monkeypatch.setattr(f"{namespace}.AIProjectClient", self.client_factory) + monkeypatch.setattr(f"{identity_namespace}.DefaultAzureCredential", self.credential_factory) + monkeypatch.setattr("builtins.input", self._read_input) + self.sample = _load_sample(monkeypatch, filename) + if self.is_text: + speaker_type = self.sample._SpeakerPlayer + + def create_speaker(): + player = speaker_type() + player.play = MagicMock(wraps=player.play) + player.close = MagicMock(wraps=player.close) + self.players.append(player) + return player + + monkeypatch.setattr(self.sample, "_SpeakerPlayer", MagicMock(side_effect=create_speaker)) + if self.is_async: + monkeypatch.setattr( + self.sample.asyncio, "to_thread", AsyncMock(side_effect=lambda function, *args: function(*args)) + ) + + def _receive(self, **kwargs): + if "timeout" in kwargs: + assert kwargs["timeout"] > 0 + assert self.events, "The sample received beyond its scripted event sequence." + event = self.events.popleft() + if isinstance(event, BaseException): + raise event + self.actions.append(("receive", event)) + return event + + async def _iterate(self): + while True: + yield await self.connection.recv() + + def _read_input(self, prompt): + assert prompt + assert self.prompts, "The sample requested unexpected interactive input." + value = self.prompts.popleft() + if isinstance(value, BaseException): + raise value + self.actions.append(("input", value)) + return value + + def _create_item(self, *, item): + self.actions.append(("item", item)) + + def _create_response(self): + self.actions.append(("response.create", None)) + + def _cancel_response(self, **kwargs): + self.actions.append(("response.cancel", kwargs)) + + async def run(self): + if self.is_async and self.is_text: + await self.sample.text_conversation() + elif self.is_text: + self.sample.text_conversation() + else: + await self.sample.main() + + def assert_call(self, mock, *args, **kwargs): + if self.is_async: + mock.assert_awaited_once_with(*args, **kwargs) + else: + mock.assert_called_once_with(*args, **kwargs) + + def assert_cleanup(self, *, created=True, connected=True): + if created: + self.assert_call(self.client.agents.delete_version, agent_name=_AGENT_NAME, agent_version=_OWNED_VERSION) + else: + self.client.agents.delete_version.assert_not_called() + self.client.agents.delete.assert_not_called() + self.client.beta.voice_agents.live.connect.assert_not_called() + for resource in (self.client, self.credential): + if self.is_async: + resource.__aenter__.assert_awaited_once() + resource.__aexit__.assert_awaited_once() + else: + resource.__enter__.assert_called_once() + resource.__exit__.assert_called_once() + exit_mock = self.manager.__aexit__ if self.is_async else self.manager.__exit__ + if not connected: + exit_mock.assert_not_called() + elif self.is_async: + exit_mock.assert_awaited_once() + else: + exit_mock.assert_called_once() + for player in self.players: + player.close.assert_called_once_with() + if self.is_async: + for operation in ( + self.client.agents.create_version, + self.client.agents.delete_version, + self.conversations.get, + self.connection.recv, + self.connection.conversation.item.create, + self.connection.response.create, + self.connection.response.cancel, + ): + assert operation.await_count == operation.call_count + self.credential_factory.assert_called_once_with() + self.client_factory.assert_called_once_with(endpoint=_ENDPOINT, credential=self.credential, allow_preview=True) + + +@pytest.fixture(params=_TEXT_SAMPLES, ids=["async-text"]) +def text_sample(monkeypatch, request): + return _SampleHarness(monkeypatch, request.param) + + +@pytest.fixture +def tool_sample(monkeypatch): + return _SampleHarness(monkeypatch, _TOOL_SAMPLE) + + +@pytest.fixture(params=(*_TEXT_SAMPLES, _TOOL_SAMPLE), ids=["async-text", "function-tool"]) +def entrypoint_sample(monkeypatch, request): + return _SampleHarness(monkeypatch, request.param) + + +async def test_text_entrypoint_drains_greeting_and_reuses_one_persisted_conversation( + text_sample, realtime_output_event, capsys +): + greeting_done = _response_done("greeting") + first_done = _response_done("first") + second_done = _response_done("second") + audio = [b"\x01\x00" * 4, b"\x02\x00" * 6, b"\x03\x00" * 8] + text_sample.prompts.extend([" Remember Ada. ", "What name did I give?", "QUIT"]) + text_sample.events.extend( + [ + {"type": "future.event", "count": 0}, + _session_created(), + _response_created("greeting"), + realtime_output_event("audio.delta", "greeting", delta=audio[0]), + realtime_output_event("audio.done", "greeting"), + realtime_output_event("audio_transcript.delta", "greeting", delta="Greeting "), + realtime_output_event("audio_transcript.delta", "greeting", delta="transcript."), + realtime_output_event("audio_transcript.done", "greeting", transcript="Greeting transcript."), + greeting_done, + _response_created("first"), + realtime_output_event("audio.delta", "first", delta=audio[1]), + realtime_output_event("audio.done", "first"), + realtime_output_event("audio_transcript.delta", "first", delta="First turn "), + realtime_output_event("audio_transcript.delta", "first", delta="transcript."), + realtime_output_event("audio_transcript.done", "first", transcript="First turn transcript."), + first_done, + _response_created("second"), + realtime_output_event("audio.delta", "second", delta=audio[2]), + realtime_output_event("audio.done", "second"), + realtime_output_event("audio_transcript.delta", "second", delta="Second turn "), + realtime_output_event("audio_transcript.delta", "second", delta="transcript."), + realtime_output_event("audio_transcript.done", "second", transcript="Second turn transcript."), + second_done, + ] + ) + + await text_sample.run() + + connection = text_sample.connection + items = [submitted.kwargs["item"] for submitted in connection.conversation.item.create.call_args_list] + assert [item.as_dict() for item in items] == [ + {"type": "message", "role": "user", "content": [{"type": "input_text", "text": prompt}]} + for prompt in ("Remember Ada.", "What name did I give?") + ] + actions = text_sample.actions + assert actions.index(("receive", greeting_done)) < actions.index(("item", items[0])) + assert actions.index(("item", items[0])) < actions.index(("receive", first_done)) + assert actions.index(("receive", first_done)) < actions.index(("item", items[1])) + assert actions.index(("item", items[1])) < actions.index(("receive", second_done)) + assert connection.response.create.call_args_list == [call(), call()] + connection.response.cancel.assert_not_called() + text_sample.client.beta.voice_agents.realtime.connect.assert_called_once_with(agent_name=_AGENT_NAME) + text_sample.assert_call(text_sample.conversations.get, _AGENT_NAME, _CONVERSATION_ID) + text_sample.conversations.list_items.assert_called_once_with(_AGENT_NAME, _CONVERSATION_ID) + definition = text_sample.client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition, models.VoiceAgentDefinition) + assert definition.model_type == models.VoiceModelType.MANAGED + assert definition.model == "realtime-deployment-offline" + assert definition.store is True + assert definition.output_modalities == [models.VoiceOutputModality.AUDIO] + assert isinstance(definition.greeting, models.VoiceAgentTemplateGreetingConfig) + assert text_sample.sample.pyaudio is None + assert len(text_sample.players) == 1 + assert text_sample.players[0].play.call_args_list == [call(chunk) for chunk in audio] + assert text_sample.players[0].bytes_received == sum(len(chunk) for chunk in audio) + assert not text_sample.events + text_sample.assert_cleanup() + output = capsys.readouterr().out + for transcript in ("Greeting transcript.", "First turn transcript.", "Second turn transcript."): + assert output.count(f"Agent: {transcript}\n") == 1 + + +async def test_text_entrypoint_displays_completed_output_text_once(text_sample, realtime_output_event, capsys): + text_sample.prompts.extend(["Reply using text.", "exit"]) + text_sample.events.extend( + [ + _session_created(), + _response_done("greeting"), + _response_created("text-response"), + realtime_output_event("text.delta", "text-response", delta="Text-only "), + realtime_output_event("text.delta", "text-response", delta="reply."), + realtime_output_event("text.done", "text-response", text="Text-only reply."), + _response_done("text-response"), + ] + ) + + await text_sample.run() + + text_sample.assert_call(text_sample.connection.response.create) + text_sample.connection.response.cancel.assert_not_called() + text_sample.players[0].play.assert_not_called() + assert not text_sample.events + text_sample.assert_cleanup() + output = capsys.readouterr().out + assert output.count("Agent: Text-only reply.\n") == 1 + assert "Agent: Text-only \n" not in output + assert "Agent: reply.\n" not in output + + +async def test_text_entrypoint_drains_matching_cancellation_before_the_next_turn(text_sample, capsys): + cancelled_done = _response_done("cancelled-response", status="cancelled") + fresh_done = _response_done("fresh-response") + timeout = asyncio.TimeoutError() if text_sample.is_async else TimeoutError() + text_sample.prompts.extend(["First turn", "Second turn", "exit"]) + text_sample.events.extend( + [ + _session_created(), + _response_done("greeting"), + _response_created("cancelled-response"), + timeout, + _response_done("unrelated-response"), + cancelled_done, + _response_created("fresh-response"), + _transcript_done("fresh-response", "Fresh reply after cancellation."), + fresh_done, + ] + ) + + await text_sample.run() + + text_sample.assert_call(text_sample.connection.response.cancel, response_id="cancelled-response") + submitted = text_sample.connection.conversation.item.create.call_args_list + assert len(submitted) == 2 + second_item = submitted[1].kwargs["item"] + assert second_item.content[0].text == "Second turn" + assert text_sample.actions.index(("receive", cancelled_done)) < text_sample.actions.index(("item", second_item)) + assert text_sample.actions.index(("item", second_item)) < text_sample.actions.index(("receive", fresh_done)) + assert text_sample.connection.response.create.call_args_list == [call(), call()] + assert not text_sample.events + text_sample.assert_cleanup() + assert "Agent: Fresh reply after cancellation." in capsys.readouterr().out + + +@pytest.mark.parametrize("phase", ["create", "receive"]) +async def test_entrypoint_failures_clean_up_only_resources_the_sample_owns(entrypoint_sample, phase): + harness = entrypoint_sample + failure = RuntimeError(f"offline {phase} failure") + if phase == "create": + harness.client.agents.create_version.side_effect = failure + elif phase == "connect": + enter = harness.manager.__aenter__ if harness.is_async else harness.manager.__enter__ + enter.side_effect = failure + else: + harness.events.append(failure) + + with pytest.raises(RuntimeError, match=f"offline {phase} failure"): + await harness.run() + + if phase == "create": + harness.client.beta.voice_agents.realtime.connect.assert_not_called() + assert not harness.players + harness.conversations.get.assert_not_called() + harness.assert_cleanup(created=phase != "create", connected=phase == "receive") + + +@pytest.mark.parametrize("cities", [("Seattle", "Oslo")], ids=["multiple-tools"]) +async def test_function_tool_entrypoint_returns_canonical_call_ids_after_the_completed_cycle( + tool_sample, cities, realtime_output_event, capsys +): + arguments = [ + _function_arguments(call_id=f"canonical-call-{index}", arguments=json.dumps({"city": city})) + for index, city in enumerate(cities) + ] + function_done = _response_done( + "tool-response", + output=[ + { + "type": "function_call", + "id": event.item_id, + "call_id": event.call_id, + "name": event.name, + "arguments": event.arguments, + } + for event in arguments + ], + ) + final_done = _response_done("final-response") + tool_sample.events.extend( + [ + _session_created(), + _response_created("tool-response"), + *arguments, + function_done, + realtime_output_event("text.delta", "final-response", delta="Tool results "), + realtime_output_event("text.delta", "final-response", delta="received."), + realtime_output_event("text.done", "final-response", text="Tool results received."), + final_done, + ] + ) + + await tool_sample.run() + + submitted = tool_sample.connection.conversation.item.create.call_args_list + assert len(submitted) == len(cities) + 1 + assert isinstance(submitted[0].kwargs["item"], models.RealtimeConversationItemMessageUser) + done_index = tool_sample.actions.index(("receive", function_done)) + continuation_indices = [index for index, action in enumerate(tool_sample.actions) if action[0] == "response.create"] + assert len(continuation_indices) == 2 + for submitted_call, event, city in zip(submitted[1:], arguments, cities): + result = submitted_call.kwargs["item"] + assert isinstance(result, models.RealtimeConversationItemFunctionCallOutput) + assert result.call_id == event.call_id + assert result.call_id != event.item_id + assert json.loads(result.output) == {"city": city, "condition": "sunny", "temperature_f": 72} + result_index = tool_sample.actions.index(("item", result)) + assert done_index < result_index < continuation_indices[1] + assert continuation_indices[1] < tool_sample.actions.index(("receive", final_done)) + assert tool_sample.connection.response.create.call_args_list == [call(), call()] + tool_sample.connection.response.cancel.assert_not_called() + definition = tool_sample.client.agents.create_version.call_args.kwargs["definition"] + assert isinstance(definition, models.VoiceAgentDefinition) + assert definition.output_modalities == [models.VoiceOutputModality.TEXT] + assert len(definition.tools) == 1 + assert isinstance(definition.tools[0], models.VoiceAgentFunctionTool) + assert definition.tools[0].name == "get_weather" + assert not tool_sample.events + tool_sample.assert_cleanup() + assert capsys.readouterr().out.count("Agent: Tool results received.\n") == 1 + + +async def test_function_tool_entrypoint_returns_unknown_tool_errors_with_the_original_call_id(tool_sample): + arguments = _function_arguments(name="unknown_tool", arguments="{}") + tool_sample.events.extend([arguments, _response_done("tool-response"), _response_done("final-response")]) + + await tool_sample.run() + + submitted = tool_sample.connection.conversation.item.create.call_args_list + assert len(submitted) == 2 + result = submitted[1].kwargs["item"] + assert result.call_id == arguments.call_id + assert json.loads(result.output) == {"error": "Unknown tool: unknown_tool"} + assert tool_sample.connection.response.create.call_args_list == [call(), call()] + tool_sample.assert_cleanup() + + +@pytest.mark.parametrize("failure", ["service-error", "invalid-arguments"]) +async def test_function_tool_entrypoint_error_paths_release_its_version_and_context(tool_sample, failure, capsys): + expected_exception = None + if failure == "timeout": + tool_sample.events.append(TimeoutError()) + elif failure == "service-error": + tool_sample.events.append(_error()) + elif failure == "transport-error": + tool_sample.events.append(ConnectionResetError("offline transport failed")) + expected_exception = ConnectionResetError + else: + tool_sample.events.append(_function_arguments(arguments="{invalid-json")) + expected_exception = json.JSONDecodeError + + if expected_exception is None: + await tool_sample.run() + else: + with pytest.raises(expected_exception): + await tool_sample.run() + + assert tool_sample.connection.conversation.item.create.call_count == 1 + assert tool_sample.connection.response.create.call_args_list == [call()] + if failure == "timeout": + tool_sample.connection.response.cancel.assert_called_once_with() + assert "Timed out waiting" in capsys.readouterr().out + else: + tool_sample.connection.response.cancel.assert_not_called() + if failure == "service-error": + assert "Session error: offline command rejected" in capsys.readouterr().out + tool_sample.assert_cleanup() diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_voice_audio_sample.py b/sdk/ai/azure-ai-projects/tests/samples/test_voice_audio_sample.py index c12485e5d058..b31884239113 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/test_voice_audio_sample.py +++ b/sdk/ai/azure-ai-projects/tests/samples/test_voice_audio_sample.py @@ -14,7 +14,9 @@ import pytest +from azure.ai.projects import models from azure.ai.projects.models import VoiceResponse +from test_realtime_samples import realtime_output_event @pytest.fixture @@ -22,6 +24,7 @@ def sample(monkeypatch): pyaudio = ModuleType("pyaudio") setattr(pyaudio, "PyAudio", MagicMock()) monkeypatch.setitem(sys.modules, "pyaudio", pyaudio) + monkeypatch.setattr("dotenv.load_dotenv", lambda: False) path = Path(__file__).parents[2] / "samples" / "agents" / "voice" return runpy.run_path(str(path / "sample_voice_agent_realtime_audio_conversation_async.py")) @@ -97,6 +100,86 @@ def test_output_audio_counts_received_payload_not_playback_estimate(sample) -> N assert processor.seconds == (len(first) + len(second)) / 48000 +@pytest.mark.asyncio +async def test_audio_conversation_handles_output_events_and_barge_in_without_hardware( + sample, monkeypatch, realtime_output_event, capsys +) -> None: + client = MagicMock() + connection = MagicMock() + connection.response.cancel = AsyncMock() + manager = client.beta.voice_agents.realtime.connect.return_value + manager.__aenter__.return_value = connection + manager.__aexit__.return_value = False + processor = sample["_AudioProcessor"](connection) + processor.start_playback = MagicMock() + processor.start_capture = MagicMock() + processor.queue_audio = MagicMock(wraps=processor.queue_audio) + processor.skip_pending_audio = MagicMock(wraps=processor.skip_pending_audio) + processor.stop_capture = AsyncMock(wraps=processor.stop_capture) + processor.shutdown = MagicMock(wraps=processor.shutdown) + run_conversation = sample["_run_audio_conversation"] + monkeypatch.setitem(run_conversation.__globals__, "_AudioProcessor", MagicMock(return_value=processor)) + audio = [b"\x01\x00" * 4, b"\x02\x00" * 6] + connection.__aiter__.return_value = [ + models.RealtimeServerEventSessionCreated( + { + "event_id": "session-created", + "session": {"id": "session-offline"}, + "conversation_id": "conversation-offline", + } + ), + models.RealtimeServerEventResponseCreated( + {"event_id": "response-created", "response": {"id": "audio-response", "status": "in_progress"}} + ), + realtime_output_event("audio.delta", "audio-response", delta=audio[0]), + realtime_output_event("audio_transcript.delta", "audio-response", delta="Spoken "), + realtime_output_event("audio.delta", "audio-response", delta=audio[1]), + realtime_output_event("audio_transcript.delta", "audio-response", delta="reply."), + models.RealtimeServerEventInputAudioBufferSpeechStarted( + {"event_id": "barge-in", "audio_start_ms": 0, "item_id": "user-interruption"} + ), + realtime_output_event("audio.done", "audio-response"), + realtime_output_event("audio_transcript.done", "audio-response", transcript="Spoken reply."), + models.RealtimeServerEventResponseDone( + { + "event_id": "response-cancelled", + "response": {"id": "audio-response", "status": "cancelled", "output": []}, + } + ), + models.RealtimeServerEventInputAudioBufferSpeechStarted( + {"event_id": "next-turn", "audio_start_ms": 0, "item_id": "user-next"} + ), + models.RealtimeServerEventResponseCreated( + {"event_id": "text-created", "response": {"id": "text-response", "status": "in_progress"}} + ), + realtime_output_event("text.delta", "text-response", delta="Text-only "), + realtime_output_event("text.delta", "text-response", delta="reply."), + realtime_output_event("text.done", "text-response", text="Text-only reply."), + models.RealtimeServerEventResponseDone( + {"event_id": "text-completed", "response": {"id": "text-response", "status": "completed", "output": []}} + ), + ] + + conversation_id = await run_conversation(client, "agent-offline") + + assert conversation_id == "conversation-offline" + client.beta.voice_agents.realtime.connect.assert_called_once_with(agent_name="agent-offline") + client.beta.voice_agents.live.connect.assert_not_called() + connection.response.cancel.assert_awaited_once_with() + processor.start_playback.assert_called_once_with() + processor.start_capture.assert_called_once_with() + assert [submitted.args[0] for submitted in processor.queue_audio.call_args_list] == audio + assert processor.output_bytes_received == sum(len(chunk) for chunk in audio) + assert processor.skip_pending_audio.call_count == 2 + processor.stop_capture.assert_awaited_once_with() + processor.shutdown.assert_called_once_with() + processor._audio.terminate.assert_called_once_with() + manager.__aexit__.assert_awaited_once() + output = capsys.readouterr().out + assert output.count("Agent: Spoken reply.\n") == 1 + assert output.count("Agent: Text-only reply.\n") == 1 + + def test_conversation_delete_snippet_accepts_no_content_result(capsys) -> None: path = Path(__file__).parents[2] / "samples" / "agents" / "voice" / "sample_voice_agent_read_conversation.py" lines = [ diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_voice_new_protocol_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_voice_new_protocol_samples.py new file mode 100644 index 000000000000..6e2192128cf5 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/samples/test_voice_new_protocol_samples.py @@ -0,0 +1,165 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline guards for sync REST samples and async WebSocket samples.""" + +import base64 +import io +from pathlib import Path +import runpy +from types import SimpleNamespace +from unittest.mock import AsyncMock, MagicMock +import wave + +import pytest + +from azure.ai.projects import models +from azure.core.exceptions import ResourceNotFoundError + +_SAMPLES = Path(__file__).parents[2] / "samples" / "agents" / "voice" + + +def _environment(monkeypatch): + monkeypatch.syspath_prepend(str(_SAMPLES)) + monkeypatch.setattr("dotenv.load_dotenv", lambda: None) + monkeypatch.setenv("FOUNDRY_PROJECT_ENDPOINT", "https://example.invalid/api/projects/test") + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_MODEL", "realtime-deployment-test") + monkeypatch.delenv("FOUNDRY_VOICE_RECORDING_OUTPUT_PATH", raising=False) + + +@pytest.fixture +def websocket_sample(monkeypatch): + _environment(monkeypatch) + monkeypatch.delenv("FOUNDRY_VOICE_AGENT_NAME", raising=False) + credential = MagicMock() + credential.__aenter__ = AsyncMock(return_value=credential) + credential.__aexit__ = AsyncMock(return_value=False) + client = MagicMock() + client.__aenter__ = AsyncMock(return_value=client) + client.__aexit__ = AsyncMock(return_value=False) + client.agents.create_version = AsyncMock(return_value=SimpleNamespace(version="owned-version")) + client.agents.delete_version = AsyncMock() + client.beta.voice_agents.conversations.delete = AsyncMock() + connection = MagicMock() + connection.recv = AsyncMock( + side_effect=[ + {"type": "session.created", "conversation_id": "conversation-test"}, + {"type": "response.created", "response": {"id": "response-test"}}, + { + "type": "response.output_audio.delta", + "response_id": "response-test", + "item_id": "item-test", + "delta": base64.b64encode(b"\x00\x08" * 4800).decode(), + }, + {"type": "response.done", "response": {"id": "response-test", "status": "cancelled"}}, + {"type": "conversation.item.truncated", "item_id": "item-test", "audio_end_ms": 0}, + ] + ) + connection.response.create = AsyncMock() + connection.response.cancel = AsyncMock() + connection.conversation.item.create = AsyncMock() + connection.conversation.item.truncate = AsyncMock() + manager = client.beta.voice_agents.realtime.connect.return_value + manager.__aenter__ = AsyncMock(return_value=connection) + manager.__aexit__ = AsyncMock(return_value=False) + monkeypatch.setattr("azure.identity.aio.DefaultAzureCredential", MagicMock(return_value=credential)) + monkeypatch.setattr("azure.ai.projects.aio.AIProjectClient", MagicMock(return_value=client)) + sample = runpy.run_path(str(_SAMPLES / "sample_voice_agent_realtime_interruption_async.py")) + return SimpleNamespace(sample=sample, client=client, connection=connection) + + +@pytest.mark.asyncio +async def test_async_interruption_confirms_control_events_and_cleans_owned_resources(websocket_sample): + env = websocket_sample + await env.sample["main"]() + name = env.client.agents.create_version.call_args.kwargs["agent_name"] + env.connection.response.cancel.assert_awaited_once_with(response_id="response-test") + env.connection.conversation.item.truncate.assert_awaited_once_with( + item_id="item-test", content_index=0, audio_end_ms=0 + ) + env.client.beta.voice_agents.conversations.delete.assert_awaited_once_with(name, "conversation-test") + env.client.agents.delete_version.assert_awaited_once_with(agent_name=name, agent_version="owned-version") + env.client.beta.voice_agents.conversations.download_generated_audio_item.assert_not_called() + + +@pytest.mark.asyncio +async def test_async_interruption_create_failure_cannot_delete_existing_resources(websocket_sample): + env = websocket_sample + env.client.agents.create_version.side_effect = RuntimeError("create failed") + with pytest.raises(RuntimeError, match="create failed"): + await env.sample["main"]() + env.client.agents.delete_version.assert_not_called() + env.client.beta.voice_agents.conversations.delete.assert_not_called() + + +@pytest.mark.asyncio +async def test_async_interruption_stream_failure_still_cleans_its_owned_resources(websocket_sample): + env = websocket_sample + env.connection.recv.side_effect = [ + {"type": "session.created", "conversation_id": "conversation-test"}, + {"type": "error", "error": {"code": "invalid_request", "message": "synthetic failure"}}, + ] + with pytest.raises(RuntimeError, match="synthetic failure"): + await env.sample["main"]() + name = env.client.agents.create_version.call_args.kwargs["agent_name"] + env.client.beta.voice_agents.conversations.delete.assert_awaited_once_with(name, "conversation-test") + env.client.agents.delete_version.assert_awaited_once_with(agent_name=name, agent_version="owned-version") + + +@pytest.fixture +def rest_sample(monkeypatch): + _environment(monkeypatch) + monkeypatch.setenv("FOUNDRY_VOICE_AGENT_NAME", "existing-agent") + monkeypatch.setenv("FOUNDRY_VOICE_CONVERSATION_ID", "conversation-test") + monkeypatch.setenv("FOUNDRY_VOICE_ITEM_ID", "stored-item-test") + credential = MagicMock() + credential.__enter__.return_value = credential + client = MagicMock() + client.__enter__.return_value = client + conversations = client.beta.voice_agents.conversations + conversations.get_generated_audio_item.return_value = models.VoiceGeneratedAudioItem( + conversation_id="conversation-test", item_id="stored-item-test", format="wav" + ) + output = io.BytesIO() + with wave.open(output, "wb") as recording: + recording.setparams((1, 2, 24000, 0, "NONE", "not compressed")) + recording.writeframes(b"\x00\x08" * 1200) + conversations.download_generated_audio_item.return_value = iter([output.getvalue()]) + monkeypatch.setattr("azure.identity.DefaultAzureCredential", MagicMock(return_value=credential)) + monkeypatch.setattr("azure.ai.projects.AIProjectClient", MagicMock(return_value=client)) + sample = runpy.run_path(str(_SAMPLES / "sample_voice_agent_read_generated_audio.py")) + return SimpleNamespace(sample=sample, client=client, conversations=conversations) + + +def test_sync_rest_sample_only_reads_existing_resources(rest_sample): + env = rest_sample + env.sample["main"]() + env.conversations.get_generated_audio_item.assert_called_once_with( + "existing-agent", "conversation-test", "stored-item-test" + ) + env.conversations.download_generated_audio_item.assert_called_once_with( + "existing-agent", "conversation-test", "stored-item-test" + ) + env.client.agents.create_version.assert_not_called() + env.conversations.delete.assert_not_called() + env.client.beta.voice_agents.realtime.connect.assert_not_called() + env.client.beta.voice_agents.live.connect.assert_not_called() + + +def test_sync_rest_sample_reports_missing_artifacts_without_success_fallback(rest_sample): + env = rest_sample + env.conversations.get_generated_audio_item.side_effect = ResourceNotFoundError("missing artifact") + with pytest.raises(ResourceNotFoundError): + env.sample["main"]() + env.conversations.download_generated_audio_item.assert_not_called() + + +def test_sync_rest_sample_never_overwrites_an_existing_output(rest_sample, monkeypatch, tmp_path): + destination = tmp_path / "existing.wav" + destination.write_bytes(b"keep") + monkeypatch.setenv("FOUNDRY_VOICE_RECORDING_OUTPUT_PATH", str(destination)) + with pytest.raises(FileExistsError): + rest_sample.sample["main"]() + assert destination.read_bytes() == b"keep" + rest_sample.conversations.get_generated_audio_item.assert_not_called() diff --git a/sdk/ai/azure-ai-projects/tsp-location.yaml.saved b/sdk/ai/azure-ai-projects/tsp-location.yaml similarity index 97% rename from sdk/ai/azure-ai-projects/tsp-location.yaml.saved rename to sdk/ai/azure-ai-projects/tsp-location.yaml index 8bbe64fda75e..31db3982e069 100644 --- a/sdk/ai/azure-ai-projects/tsp-location.yaml.saved +++ b/sdk/ai/azure-ai-projects/tsp-location.yaml @@ -1,5 +1,5 @@ directory: specification/ai-foundry/data-plane/Foundry/src/sdk-python-js-azure-ai-projects -commit: 18b6779b9c0d37ec2fc17cb7371b4fc066a374de +commit: 3e2177ff982e0e0af47a19f1bed59187f9084929 repo: Azure/azure-rest-api-specs additionalDirectories: - specification/ai-foundry/data-plane/Foundry/src/agents diff --git a/sdk/ai/cspell.yaml b/sdk/ai/cspell.yaml index 77c06edae911..37114e13e3d6 100644 --- a/sdk/ai/cspell.yaml +++ b/sdk/ai/cspell.yaml @@ -24,6 +24,7 @@ words: - azureopenai - balapvbyostoragecanary - BLPHARMA + - brise - capsys - cegr - closefd @@ -44,6 +45,7 @@ words: - faiss - Fdeployments - FineTuning + - flitz - fmatter - Fproviders - Fresource @@ -58,9 +60,11 @@ words: - getconnectionwithcredentials - GLEU - GRNWAVE + - harema - Hola - HORIZCHEM - inpainting + - juni - ldel - levelno - libasound @@ -79,6 +83,9 @@ words: - mros - NBFCS - nify + - nira + - noeul + - nuri - OCEACARGO - okwargs - openai @@ -103,6 +110,7 @@ words: - runid - runsvdir - sess + - shida - simpleqna - skoid - STLAUTO @@ -116,6 +124,8 @@ words: - ubinary - Udbk - ulaw + - unmute + - unmuted - unsanitized - UPIA - vcpu