Add Voice Agents to Foundry Python SDK - #48939
Conversation
Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
…ient and samples, remove azure-ai-voiceagents - Emit azure-ai-projects from TypeSpec at PR #45357 (unify voice agents with Agents API) - Add hand-written async realtime WebSocket client (AIProjectClient.realtime), ported from azure-ai-voiceagents - Add 9 new samples under samples/agents/voice/ - Update patch files, tests, README, and docs/public-methods.md for the new voice agent surface - Remove sdk/voiceagents/azure-ai-voiceagents (superseded by unified azure-ai-projects voice agents)
…s, JSON validation on raw string events
- Revert VOICE_AGENTS_V1_PREVIEW from _AGENT_OPERATION_FEATURE_HEADERS (service not ready, breaks existing recordings) - Fix mypy: undefined _unions self-reference, missing realtime/. AsyncRealtime* stubs in aio/_patch.pyi, add targeted overrides for known generated overload-widening signatures in patch_agents/patch_evaluation_rules - Fix pylint: reimported AgentKind in types.py, self-import in _unions.py - Fix voice/optimization sample type errors with targeted type: ignore comments - Add pcma/pcmu to sdk/ai/cspell.yaml word list
Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
…ec (PR 45357); add sync live-text-conversation sample
…e APIs Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>
- Work around aiohttp response-decompression bug on agents/agent_endpoint_conversations (async client) - Fix pyright errors: self-referencing forward-refs in _unions.py, subprotocols typing in _realtime.py - Fix Sphinx doc build failure (malformed RST in get_session_log_stream docstring) - Remove non-functional generated voice_agent_web_socket operation group from public client surface - Guard connection_url override against token exfiltration to untrusted hosts in realtime client - Don't swallow BaseException (e.g. CancelledError) when wrapping realtime connection failures - Add recorded tests for voice-agent CRUD (sync/async) and agent_endpoint_conversations header injection - Update stale expected Foundry-Features header constants to include VoiceAgents=V1Preview
…azure-sdk-for-python into xitzhang/voice-agent-pupr
…ientEvent/ConversationItem/ServerEvent from _patch; sanitize Foundry-Features header in test recordings
…d sample playback azure-storage-blob's generated client hardcodes Accept: application/xml for blob uploads, but some CI environments have been observed sending Accept: */* instead (a transport/dependency-version difference unrelated to any SDK code here). The test-proxy's strict default matcher treats this single header difference as a full playback miss even when the URL, method, query params, and body all match exactly, intermittently failing sample_models_create_and_poll, sample_datasets, sample_datasets_download, and sample_models_basic_async - confirmed already flaky on main independent of this branch (main build 6791141/6796410/6800289 failed with this exact signature, 6790806/6800869 passed). Add add_remove_header_sanitizer(headers="Accept") to tests/conftest.py, following the same established pattern already used here for Foundry-Features and Content-Encoding: strip a benign, non-tested header from matching instead of exact-matching it. Verified by forcing an Accept: */* mismatch locally (reproduces the exact CI failure without this fix, passes with it), and reran the full suite (1489 passed, 123 skipped, 0 failed, unchanged from before). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ephony tests - _realtime.py / aio/_realtime.py: fix critical bug sending a literal placeholder Authorization header instead of a real Bearer token; URL-encode agent_name in the websocket URL. - Remove dead VoiceAgentWebSocketOperations export from operations/__init__.py and aio/operations/__init__.py; extend PostEmitter.ps1 to strip it on future regeneration; regenerate api.md/api.metadata.yml accordingly. - sample_voice_agent_live_text_conversation.py/_async.py: fix a bug where the agent's auto-greeting response raced with the reply to the user's first message, silently dropping the real answer; drain/display the greeting before the interactive loop. - sample_voice_agent_live_audio_conversation_async.py: fix the same field-dropping bug by reusing the generated agent definition as-is instead of reconstructing a partial one. - Add actual (not estimated) audio payload size tracking to all three streaming samples: byte counts, human-readable size, and format/sample rate/channels/duration are now printed for sent/received audio. - Add mocked protocol-level tests for all 13 agent_telephony operations (call jobs + campaigns); live/recorded tests are not yet possible since the routes return 400 UnsupportedApiVersion on the current test resource. - Update test_realtime_client.py/_async.py assertions for the auth fix. - Move PSTN/pstn cspell entries from the repo-wide .vscode/cspell.json to the package-level sdk/ai/cspell.yaml, which can resolve them on its own. - Correct FOUNDRY_VOICE_MODEL_NAME description in .env.template. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e-release fix into Features Added, add Sample updates section Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 1 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
🟡 Changes recommended
There are at least two concrete repo-impacting issues (a type-checking problem in a new sample and an incorrectly named tsp-location file) that should be corrected before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds Voice Agents support to azure-ai-projects, introducing a new voice-agent kind integrated into the existing Agents API, plus realtime (WebSocket) client support, new operation groups for conversation readback and telephony, and accompanying samples/tests and test-resource provisioning updates.
Changes:
- Adds voice-agent API surface (CRUD/versioning, conversation read-back, telephony) and updates feature-header behaviors for preview opt-in.
- Introduces sync/async realtime streaming clients (
client.realtime/async_client.realtime) with optional dependencies and extensive samples. - Adds new recorded/unit/live tests plus test resource provisioning assets for live realtime scenarios.
File summaries
| File | Description |
|---|---|
| sdk/ai/cspell.yaml | Adds voice-agent related terms to spellcheck allowlist. |
| sdk/ai/azure-ai-projects/tsp-location.yaml.saved | Tracks TypeSpec source location/commit for regeneration (but file naming needs attention). |
| sdk/ai/azure-ai-projects/tests/test_base.py | Adds a sanitized env var placeholder for voice model deployment in tests. |
| sdk/ai/azure-ai-projects/tests/samples/test_samples.py | Adds voice samples to sample test matrix with appropriate skips for WS/unrecordable flows. |
| sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py | Adds async voice samples to sample test matrix with WS-related skips. |
| sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_ga_operations.py | Expands header override coverage to include different header casing variants. |
| sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_ga_operations_async.py | Async counterpart for header override casing tests. |
| sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol.py | Adds protocol-level request construction tests for telephony call-job/campaign routes. |
| sdk/ai/azure-ai-projects/tests/foundry_features_header/test_agent_telephony_protocol_async.py | Async protocol tests for telephony request construction. |
| sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py | Updates expected Foundry-Features opt-ins and adds coverage for conversations/telephony groups. |
| sdk/ai/azure-ai-projects/tests/conftest.py | Sanitizer changes to reduce cassette drift (header matching) for stable playback. |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py | Adds recorded tests for agent telephony bindings/calls/transfer targets and generated-audio reads (currently skipped pending service support). |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_campaign.py | Adds recorded tests for outbound telephony call jobs/campaigns (currently skipped pending API-version enablement). |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_campaign_async.py | Async counterpart for outbound telephony call-job/campaign tests (currently skipped). |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live.py | Adds live-only realtime WebSocket tests for sync client. |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_realtime_live_async.py | Adds live-only realtime WebSocket tests for async client. |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud.py | Adds recorded CRUD/versioning tests for voice agents via project_client.agents. |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud_async.py | Async CRUD/versioning tests for voice agents. |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_conversations.py | Adds recorded tests for conversation transcript/audio read-back with live-only setup for recording. |
| sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_conversations_async.py | Async counterpart for conversation read-back tests. |
| sdk/ai/azure-ai-projects/tests.yml | Adds a live-test pipeline configuration for voice-agent live tests in a supported region. |
| sdk/ai/azure-ai-projects/test-resources.bicep | Adds Bicep template to provision Foundry resources required for voice-agent live tests. |
| sdk/ai/azure-ai-projects/test-resources-post.ps1 | Adds post-deploy script to create the gpt-realtime deployment with retry/wait logic. |
| sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream.py | Updates session log stream sample to explicitly request streaming. |
| sdk/ai/azure-ai-projects/samples/hosted_agents/sample_session_log_stream_async.py | Async version of explicit streaming request update. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py | Adds voice-agent definition sample showing audio config and tool configuration. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_versions.py | Adds sample showing voice-agent versioning flows. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation.py | Adds sample showing conversation transcript readback via agent_endpoint_conversations. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation_audio.py | Adds sample showing conversation audio readback + file streaming. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py | Adds sample showing function tool round-trip during a live realtime session. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py | Adds sample for guided authoring via agents.generate_agent(kind="voice"). |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic.py | Adds basic sync voice-agent lifecycle sample. |
| sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic_async.py | Adds basic async voice-agent lifecycle sample. |
| sdk/ai/azure-ai-projects/samples/agents/sample_workflow_multi_agent_with_mcp_approval.py | Adjusts typing ignores for workflow action item access. |
| sdk/ai/azure-ai-projects/samples/agents/sample_workflow_multi_agent_async.py | Async counterpart typing-ignore adjustment. |
| sdk/ai/azure-ai-projects/README.md | Adds voice agents (preview) to the operation group table and links to relevant docs. |
| sdk/ai/azure-ai-projects/pyproject.toml | Bumps package to beta classifier and adds realtime optional dependencies. |
| sdk/ai/azure-ai-projects/docs/public-methods.md | Updates public method inventory and includes new operation groups/methods. |
| sdk/ai/azure-ai-projects/dev_requirements.txt | Adds websockets to development requirements. |
| sdk/ai/azure-ai-projects/CHANGELOG.md | Adds a 2.7.0b1 entry describing voice agents, realtime, conversation readback, and telephony. |
| sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py | Exports new operation group patch types. |
| sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_evaluators.py | Refactors typing aliases/imports and adds type ignores for overrides. |
| sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_evaluation_rules.py | Adds override typing ignores and tightens typing for super calls. |
| sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_datasets.py | Refactors typing alias import and adds typing ignores for overrides. |
| sdk/ai/azure-ai-projects/azure/ai/projects/operations/init.py | Exposes new operation group classes from operations namespace. |
| sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py | Adds VoiceAgents preview opt-in to the agents header composition and documents client placement. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py | Exports async patch types for new operation group. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_evaluators_async.py | Async typing alias refactor + override ignores. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_evaluation_rules_async.py | Async override typing ignores and arg-type ignore for super call. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_datasets_async.py | Async typing alias import + override ignores. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/init.py | Exposes new async operation group classes. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.pyi | Exposes realtime types and realtime property in async client typing stubs. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py | Adds async realtime property + opt-in header proxying and accept-encoding workaround. |
| sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py | Adds generated async operation group attributes for conversations and telephony. |
| sdk/ai/azure-ai-projects/azure/ai/projects/_version.py | Bumps package version to 2.7.0b1. |
| sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py | Adds ETag quoting and match-condition header preparation helpers. |
| sdk/ai/azure-ai-projects/azure/ai/projects/_unions.py | Adds new voice-agent related union types/literals. |
| sdk/ai/azure-ai-projects/azure/ai/projects/_patch.pyi | Exposes realtime types and realtime property in sync client typing stubs. |
| sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py | Adds sync realtime property + opt-in header proxying and exports realtime types. |
| sdk/ai/azure-ai-projects/azure/ai/projects/_client.py | Adds generated operation group attributes for conversations and telephony. |
| sdk/ai/azure-ai-projects/assets.json | Updates azure-sdk-assets tag reference. |
| sdk/ai/azure-ai-projects/api.metadata.yml | Updates api.md hash and package version metadata for 2.7.0b1. |
| sdk/ai/azure-ai-projects/.env.template | Adds environment variables for voice tests and voice samples. |
| scripts/devops_tasks/test_run_samples.py | Excludes interactive/live-only voice samples from non-interactive sample runner. |
| eng/tools/azure-sdk-tools/azpysdk/samples.py | Excludes interactive/live-only voice samples from azpysdk sample execution. |
Review details
- Files reviewed: 81/85 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| directory: specification/ai-foundry/data-plane/Foundry/src/sdk-python-js-azure-ai-projects | ||
| commit: 675e111febec298cdc8e640d9f8653cc287c5dd1 | ||
| commit: b538ac90619e094630e3c773d5231070809caf48 | ||
| repo: Azure/azure-rest-api-specs | ||
| additionalDirectories: | ||
| - specification/ai-foundry/data-plane/Foundry/src/agents |
…pupr-ready # Conflicts: # sdk/ai/azure-ai-projects/CHANGELOG.md # sdk/ai/azure-ai-projects/assets.json # sdk/ai/azure-ai-projects/azure/ai/projects/_version.py
…iceAgentEndConversationSystemTool, fix data-gen-jobs regression - Regenerated from TypeSpec commit fcea6bee2d387de983f3ba6dea6c0df92a79b595. - Added VoiceAgentEndConversationSystemTool, a dedicated system-tool subclass for ending a call; updated sample_voice_agent_with_tools.py to use it instead of the generic VoiceAgentSystemTool(name=...) construction, and added a CHANGELOG mention. Live-verified the full create/get/list round-trip. - Fixed a regression introduced by this TypeSpec commit in an unrelated area: SimulationSeedDataGenerationJobOptions lost its max_samples field entirely (confirmed against the actual .tsp source), while its 3 sibling job-type classes correctly kept theirs -- this broke the existing, unrelated sample_synthetic_multiturn_evaluation.py sample/test. Restored max_samples client-side via models/_patch.py (using the SDK's own rest_field mechanism), preserving existing behavior without touching generated files directly. - Fixed a non-idempotency bug in PostEmitter.ps1's get_session_log_stream fixup: its regex matched its own previously-applied output, so re-running the script (needed here due to a transient file lock) inserted a duplicate line. Narrowed the match to the raw generator output only and corrected the resulting duplicate in both _operations.py files, which now byte-match origin/main exactly for that function. - Accepted unrelated, non-breaking additions that came along via the shared TypeSpec branch (BrowserAutomationTool/BrowserAutomationToolboxTool, DataGenerationJobOutputWriteMode, trace_ids filtering) without adding Voice-Agents-unrelated samples/changelog entries for them. - Re-verified all 11 Voice Agents samples live end-to-end against voice-live-tip-resource: REST/CRUD status codes, realtime streaming events, function-tool invocation, and byte-accurate audio input/output size tracking. - Full regression suite: 1516 passed, 123 skipped, 0 failed. pylint 10.00/10. mypy clean (only pre-existing, unrelated errors). black clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The change set introduces substantial new public surface area (realtime WebSocket client + new operation groups) and modifies testing/packaging/infrastructure, requiring careful human validation of API and test strategy decisions.
Review details
- Files reviewed: 82/86 changed files
- Comments generated: 5
- Review effort level: Lite
| @pytest.mark.skip( | ||
| reason="Telephony routes are defined in the TypeSpec/SDK but not yet deployed on the live " | ||
| "test service (empty-body 404s at the routing layer). Un-skip once the service deploys them." | ||
| ) |
| return VoiceAgentDefinition( | ||
| model_type="managed", | ||
| model=model, | ||
| instructions="You are a helpful voice assistant.", |
| @pytest.mark.skip( | ||
| reason="agent_telephony routes are registered but return 400 UnsupportedApiVersion for " | ||
| "api-version 'v1' on the live test service. Un-skip once the service supports 'v1' for " | ||
| "this operation group." | ||
| ) |
| @pytest.mark.skip( | ||
| reason="agent_telephony routes are registered but return 400 UnsupportedApiVersion for " | ||
| "api-version 'v1' on the live test service. Un-skip once the service supports 'v1' for " | ||
| "this operation group." | ||
| ) |
| # Can't include those, because they are not supported in Python 3.9. Samples that use these package | ||
| # cannot be run as pytest, because the pipeline will fail on Python 3.9 jobs. |
[Pilot] PR Pipeline Failure AnalysisWhat failedBuild 6808203 ( 1) Test-proxy recording/playback failure (~9,168 of the underlying error events, the overwhelming majority of failures) Every test that uses This affects essentially every recorded test added/touched by this PR (agents telemetry instrumentor tests, responses instrumentor tests, voice agent tests, session/file CRUD tests, samples tests, etc.) on every platform - the test-proxy cannot find or match a valid recording for the test IDs, most likely because the recordings for these newly added/renamed tests are missing or 2) In The OpenAI SDK's 3) Missing telemetry spans for raw-response streaming (144 occurrences) Same test file, related tests assert spans were recorded but get zero: This cascades from the same raw-response close/parse handling issue in #2 - the instrumentation isn't finalizing/emitting a span for the raw-response streaming path being exercised by these new tests. Relevant pipeline outputRecommended next steps
|
|
Found this PR difficult to review since it has many changes for unrelated. |
Description
Adds Voice Agents to the Foundry Python SDK: a new agent kind for real-time, speech-to-speech conversational AI unified with the rest of the Agents API. Define a voice agent's model, audio, turn detection, greeting, and tools; manage it like any other agent; hold a live conversation with it over a WebSocket with barge-in and persisted conversation history/audio; and reach it through telephony (inbound bindings or outbound calls/campaigns).
This SDK is regenerated based on the following API spec changes:
Spec: foundrysdk_specs/specs/agents/voice_agents/spec.md
TypeSpec: Unify voice agents with the Agents API and add the v1 voice data plane · Azure/azure-rest-api-specs@9759481
Add Foundry Voice Agent batch 2 APIs by yulin-li · Pull Request #45852 · Azure/azure-rest-api-specs
Auto-generated (from TypeSpec)
The voice agent surface itself: VoiceAgentDefinition and its audio/turn-detection/greeting/tool/avatar config models, managed through the existing project_client.agents CRUD/versioning methods.
New agent_endpoint_conversations operation group to read back persisted transcripts and audio.
New agent_telephony operation group for outbound call jobs and campaigns, plus telephony bindings/call management on project_client.agents.
WebRTC transport, sub-agent consultation, and conversation-engine delegation on VoiceAgentDefinition.
Hand-written
A new client.realtime / async_client.realtime WebSocket client (not TypeSpec-generated, modeled after the OpenAI Python realtime client's ergonomics) for sending/receiving strongly-typed realtime events.
11 new samples under samples/agents/voice/ covering lifecycle, live audio/text conversation, function tools, versioning, and conversation read-back.
New unit (mocked) and live/recorded test coverage for the realtime client, voice agent CRUD/conversations/telephony.
CHANGELOG, README, and optional websockets/aiohttp dependency updates.
All SDK Contribution checklist:
General Guidelines and Best Practices
Testing Guidelines