Skip to content

[Do not merge][Debug] Preview for voiceagent - #48484

Open
xitzhang (xitzhang) wants to merge 57 commits into
mainfrom
xitzhang/voice-agent-pupr
Open

[Do not merge][Debug] Preview for voiceagent#48484
xitzhang (xitzhang) wants to merge 57 commits into
mainfrom
xitzhang/voice-agent-pupr

Conversation

@xitzhang

@xitzhang xitzhang (xitzhang) commented Aug 6, 2026

Copy link
Copy Markdown
Member

Description

Please add an informative description that covers that changes made by the pull request and link all relevant issues.

If an SDK is being regenerated based on a new API spec, a link to the pull request containing these API spec changes should be included above.

All SDK Contribution checklist:

  • The pull request does not introduce [breaking changes]
  • CHANGELOG is updated for new features, bug fixes or other significant changes.
  • I have read the contribution guidelines.

General Guidelines and Best Practices

  • Title of the pull request is clear and informative.
  • There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, see this page.

Testing Guidelines

  • Pull request includes test coverage for the included changes.

Copilot AI balanced review requested due to automatic review settings August 6, 2026 21:05
@xitzhang xitzhang (xitzhang) changed the title [Do not merge] Preview for voiceagent [Do not merge][Debug] Preview for voiceagent Aug 6, 2026
@azure-pipelines

Copy link
Copy Markdown
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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR introduces an initial preview of the azure-ai-voiceagents Python SDK, including generated management clients, a hand-written async realtime (WebSocket) client, and supporting samples/tests for validation and guidance.

Changes:

  • Adds the new azure-ai-voiceagents package skeleton (generated clients/models + packaging metadata).
  • Implements an async realtime WebSocket client (aio/_realtime.py) and an aiohttp transport workaround for brotli negotiation.
  • Adds unit tests, recorded tests (with sanitization), live smoke test, and scenario-based samples + sample README.

Reviewed changes

Copilot reviewed 59 out of 63 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
sdk/voiceagents/azure-ai-voiceagents/tsp-location.yaml Tracks source spec location for generation/regeneration.
sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_configuration.py Unit tests for configuration defaults/required params.
sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_client_construction.py Unit tests for sync/async client construction and operation groups.
sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_brotli_workaround.py Unit tests validating async brotli/aiohttp transport workaround behavior.
sdk/voiceagents/azure-ai-voiceagents/tests/unit/conftest.py Disables recorded-test proxy startup for unit-test runs.
sdk/voiceagents/azure-ai-voiceagents/tests/recording/test_voice_agents_client_async.py Recorded async functional tests for read-only operations.
sdk/voiceagents/azure-ai-voiceagents/tests/recording/test_voice_agents_client.py Recorded sync functional tests for read-only operations.
sdk/voiceagents/azure-ai-voiceagents/tests/recording/conftest.py Adds extra URI sanitization for project name in recordings.
sdk/voiceagents/azure-ai-voiceagents/tests/recording/_preparer.py Shared preparer/sanitized env var loader for recorded/live tests.
sdk/voiceagents/azure-ai-voiceagents/tests/live/test_smoke_live.py Always-live smoke test to catch auth/wire/serialization issues.
sdk/voiceagents/azure-ai-voiceagents/tests/live/conftest.py Disables recorded-test proxy startup for live-test runs.
sdk/voiceagents/azure-ai-voiceagents/tests/conftest.py Starts the test-proxy for recorded tests.
sdk/voiceagents/azure-ai-voiceagents/samples/quickstart/sample_quickstart_async.py End-to-end quickstart: create temp agent + realtime audio session + cleanup.
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_read_conversation_audio.py Demonstrates reading and streaming persisted conversation audio to WAV.
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_read_conversation.py Demonstrates reading persisted conversation envelope/items/responses.
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_manage_voice_agent_versions.py Demonstrates creating/listing/fetching voice agent versions (incl drafts).
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_generate_voice_agent.py Demonstrates guided-authoring agent generation and cleanup.
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_create_voice_agent_with_tools.py Demonstrates richer agent definitions (tools + audio config + BYOM).
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_create_and_manage_voice_agent_async.py Async management lifecycle sample: create/get/list/delete.
sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_create_and_manage_voice_agent.py Sync management lifecycle sample incl update and enable/disable.
sdk/voiceagents/azure-ai-voiceagents/samples/live/sample_live_text_conversation_async.py Live typed conversation + optional audio playback + readback.
sdk/voiceagents/azure-ai-voiceagents/samples/live/sample_live_audio_conversation_async.py Live mic/speaker conversation + barge-in + readback.
sdk/voiceagents/azure-ai-voiceagents/samples/README.md Scenario-organized samples index + setup/troubleshooting guidance.
sdk/voiceagents/azure-ai-voiceagents/pytest.ini Configures pytest asyncio integration (asyncio_mode=auto).
sdk/voiceagents/azure-ai-voiceagents/pyrightconfig.json Pyright configuration for local development/type-checking.
sdk/voiceagents/azure-ai-voiceagents/pyproject.toml Package metadata and dependencies for azure-ai-voiceagents.
sdk/voiceagents/azure-ai-voiceagents/dev_requirements.txt Dev dependencies including local azure-core/azure-identity and aiohttp.
sdk/voiceagents/azure-ai-voiceagents/azure_ai_voiceagents-1.0.0b1/azure/ai/voiceagents/_configuration.py Snapshot of generated configuration under versioned folder.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/py.typed PEP 561 typing marker.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/operations/_patch.py Customization hook for generated operations (sync).
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/operations/init.py Exposes sync operation groups and patch hook.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/models/_patch.py Customization hook for generated models.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/models/_enums.py Generated enums supporting voice agents + realtime schemas.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/models/init.py Public models/enums surface exports.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/operations/_patch.py Customization hook for generated operations (async).
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/operations/init.py Exposes async operation groups and patch hook.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py Hand-written async realtime WebSocket client and event typing.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_patch.py Async client patch: adds realtime namespace + brotli workaround.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_configuration.py Generated async configuration.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_client.py Generated async HTTP client and operation group wiring.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/init.py Async package exports and patch hook.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_version.py Package version constant.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_utils/init.py Generated utils package init.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_unions.py Generated public type aliases/unions.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_patch.py Sync customization hook placeholder.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_configuration.py Generated sync configuration.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_client.py Generated sync HTTP client and operation group wiring.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/init.py Sync package exports and patch hook + version.
sdk/voiceagents/azure-ai-voiceagents/azure/ai/init.py Namespace package marker for azure.ai.
sdk/voiceagents/azure-ai-voiceagents/azure/init.py Namespace package marker for azure.
sdk/voiceagents/azure-ai-voiceagents/assets.json Azure SDK assets tag configuration for CI.
sdk/voiceagents/azure-ai-voiceagents/apiview-properties.json APIView cross-language mapping metadata.
sdk/voiceagents/azure-ai-voiceagents/_metadata.json Tracks API version metadata for generation.
sdk/voiceagents/azure-ai-voiceagents/README.md Package README scaffold.
sdk/voiceagents/azure-ai-voiceagents/MANIFEST.in Source distribution inclusions (tests/samples/py.typed, etc.).
sdk/voiceagents/azure-ai-voiceagents/LICENSE MIT license text.
sdk/voiceagents/azure-ai-voiceagents/CHANGELOG.md Initial changelog entry for version b1.
Suppressed comments (3)

sdk/voiceagents/azure-ai-voiceagents/tsp-location.yaml:1

  • The PR description is still the template (missing a real summary of changes, links to relevant issues/spec PRs, and checklist updates). Please replace the placeholder description with a concise overview of what this PR adds (new SDK package, realtime WebSocket client, samples/tests) and link the spec change PR/commit referenced in tsp-location.yaml.
    sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_configuration.py:1
  • This test doesn’t actually validate overriding behavior because it passes the same value as the default (\"v1\"). Consider changing it to pass a different value (or None if supported by the client) so the test can detect regressions where the override is ignored.
    sdk/voiceagents/azure-ai-voiceagents/samples/management/sample_create_and_manage_voice_agent.py:1
  • Using a fixed, non-namespaced agent_name risks collisions across repeated runs and (more importantly) can inadvertently delete/modify a real agent if a user already has an agent with that name. Safer pattern for samples is to generate a unique name (e.g., including a UUID suffix) and only delete the resource that the sample created.

Comment thread sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_unions.py Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_unions.py Outdated
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/CHANGELOG.md Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/README.md Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/README.md Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/README.md Outdated
Copilot AI review requested due to automatic review settings August 6, 2026 22:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Note

This error may be related to your runner configuration. You can now configure runners for Copilot code review separately from Copilot cloud agent by creating a copilot-code-review.yml file with your setup steps. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 67 changed files in this pull request and generated 2 comments.

Suppressed comments (8)

sdk/voiceagents/ci.yml:1

  • The PR description is still the template text (it asks to 'add an informative description' and link issues), but the change set is substantial (new SDK + CI + tests + samples). Please update the PR description to summarize the intent/scope and link any relevant spec/issue/PR references so reviewers can validate the changes against requirements.
    sdk/voiceagents/azure-ai-voiceagents/pyproject.toml:1
  • Excluding the azure and azure.ai packages from package discovery is likely to produce an invalid wheel where the namespace package initializers (azure/__init__.py, azure/ai/__init__.py) are not installed, breaking imports in environments that rely on pkgutil-style namespace packaging. Recommended fix: remove \"azure\" and \"azure.ai\" from the exclude list (or switch to an explicit include pattern for azure* packages consistent with other Azure SDK Python packages).
    sdk/voiceagents/azure-ai-voiceagents/samples/live/sample_live_audio_conversation_async.py:1
  • The callback can return fewer than wanted bytes when it hits the end-of-stream marker (if not data: break). pyaudio callbacks must return exactly the requested frame size; otherwise playback can glitch or error. Instead of break, pad the remainder with silence (or return paComplete with a correctly-sized buffer) to satisfy pyaudio’s size contract.
    sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_configuration.py:1
  • This test name claims the API version is 'overridden', but it sets the value to the default (\"v1\"), so it doesn’t actually verify override behavior. Either rename the test to reflect what it asserts (e.g., that api_version is stored), or set api_version to a non-default value (if supported by the client) to validate that overriding works.
    sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py:648
  • Passing the WebSocket subprotocol by manually setting Sec-WebSocket-Protocol is fragile because many WS clients (including aiohttp) expect to manage/validate this header via the protocols=[...] argument. Prefer ws_connect(..., protocols=[\"realtime\"], ...) and remove the manual header to avoid handshake issues and ensure the negotiated subprotocol is tracked correctly by the client.
        headers: Dict[str, str] = {
            "Authorization": f"Bearer {token.token}",
            "Foundry-Features": str(foundry_features),
            "Sec-WebSocket-Protocol": "realtime",
        }

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py:655

  • Passing the WebSocket subprotocol by manually setting Sec-WebSocket-Protocol is fragile because many WS clients (including aiohttp) expect to manage/validate this header via the protocols=[...] argument. Prefer ws_connect(..., protocols=[\"realtime\"], ...) and remove the manual header to avoid handshake issues and ensure the negotiated subprotocol is tracked correctly by the client.
            connection = await session.ws_connect(url, headers=headers, params=params, **self._kwargs)

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_configuration.py:36

  • The docstring says the default api_version is None, but the implementation defaults it to \"v1\". Please align the docstring with the actual behavior (and consider applying the same fix in the async configuration file as well) to avoid confusing SDK consumers.
    :keyword api_version: The API version to use for this operation. Known values are "v1" and
     None. Default value is None. If not set, the operation's default API version will be used. Note
     that overriding this default value may result in unsupported behavior.

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_configuration.py:41

  • The docstring says the default api_version is None, but the implementation defaults it to \"v1\". Please align the docstring with the actual behavior (and consider applying the same fix in the async configuration file as well) to avoid confusing SDK consumers.
    def __init__(self, endpoint: str, credential: "TokenCredential", **kwargs: Any) -> None:
        api_version: str = kwargs.pop("api_version", "v1")

Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py
Comment thread sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py Outdated
Copilot AI review requested due to automatic review settings August 6, 2026 23:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 67 changed files in this pull request and generated 3 comments.

Suppressed comments (6)

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py:51

  • The exported connection's public methods and attributes use ClientEvent, ServerEvent, ConversationItem, and the resource helper classes in their annotations, but this module and aio/_patch.py export only the three connection classes. Consumers therefore see public annotations that can only be imported from the private _realtime module. Re-export all types used by this public surface from azure.ai.voiceagents.aio.
__all__ = [
    "AsyncRealtime",
    "AsyncRealtimeConnection",
    "AsyncRealtimeConnectionManager",
]

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_patch.py:45

  • Constructing aiohttp.ClientSession here eagerly requires a running event loop and binds the client to that loop. This makes otherwise valid async-client construction outside asyncio.run() fail before any request. Set the default Accept-Encoding through the headers policy instead so AioHttpTransport can retain its lazy session creation.
                kwargs["transport"] = AioHttpTransport(
                    session=aiohttp.ClientSession(auto_decompress=False, headers={"Accept-Encoding": "gzip, deflate"})
                )

sdk/voiceagents/azure-ai-voiceagents/samples/live/sample_live_audio_conversation_async.py:138

  • Barge-in does not discard a partially consumed chunk: each callback copies bytes from remaining before checking that chunk's sequence against _playback_base. A large delta can therefore continue playing across callbacks after skip_pending_audio(). Track the sequence associated with remaining and invalidate it before slicing whenever it is older than the playback base.
    sdk/voiceagents/azure-ai-voiceagents/samples/quickstart/sample_quickstart_async.py:100
  • Barge-in does not discard a partially consumed chunk: bytes are copied from remaining before the callback checks sequence validity. If a delta spans multiple callback buffers, stale audio continues playing after skip_pending_audio(). Associate remaining with its sequence and clear it before slicing when that sequence predates _playback_base.
    sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_configuration.py:47
  • This test passes the same value as the default, so it still passes if the api_version override is ignored. Use a distinct sentinel value to verify that the keyword is actually honored.
    sdk/voiceagents/azure-ai-voiceagents/samples/live/sample_live_text_conversation_async.py:179
  • After a timeout, the response remains active and its eventual events stay queued. On the next turn, pump() can consume the previous response's response.done and return before the new response completes, or the service can reject the new response while the old one is active. Cancel the timed-out response and drain/match its terminal event before accepting another prompt.

Comment thread sdk/voiceagents/azure-ai-voiceagents/pyproject.toml Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/tests/recording/test_voice_agents_client.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 67 changed files in this pull request and generated 2 comments.

Suppressed comments (8)

sdk/voiceagents/azure-ai-voiceagents/pyproject.toml:13

  • This new package is missing both api.md and api.metadata.yml. The repository API consistency gate explicitly marks an affected package missing either file as a failure (.github/workflows/src/api-md-consistency/find_mismatches.js:76-92). Generate and commit both files with azpysdk apistub azure-ai-voiceagents.
    sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_patch.py:43
  • Creating aiohttp.ClientSession in the client constructor makes VoiceAgentsClient(...) require a running event loop and binds the transport to that loop. This breaks the normal pattern of constructing an async SDK client before asyncio.run(...) (the new test even documents this limitation). Create/configure the session lazily when the transport opens instead.
                kwargs["transport"] = AioHttpTransport(
                    session=aiohttp.ClientSession(auto_decompress=False, headers={"Accept-Encoding": "gzip, deflate"})
                )

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py:242

  • agent_name is inserted into the URL as raw path text, unlike the generated operation which URL-serializes this path parameter. Reserved characters can therefore change the route instead of identifying the requested agent. Percent-encode the path segment before interpolation.
    return f"{base}/agents/{agent_name}/endpoint/protocols/voice"

sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_patch.py:65

  • The public annotations/docstrings refer to azure.ai.voiceagents.aio.ClientEvent and ServerEvent, but these aliases are defined only in the private _realtime module and are not re-exported here. Those documented imports therefore fail; include both aliases in the public aio surface.
__all__: list[str] = [
    "VoiceAgentsClient",
    "AsyncRealtime",
    "AsyncRealtimeConnection",
    "AsyncRealtimeConnectionManager",
]  # Add all objects you want publicly available to users at this package level

sdk/voiceagents/azure-ai-voiceagents/samples/quickstart/sample_quickstart_async.py:115

  • The callback consumes remaining before checking its sequence against _playback_base. After skip_pending_audio() advances the base during barge-in, bytes left from the old response are still played on the next callback, so interruption does not actually drop all pending audio. Track the sequence associated with remaining and clear it before consuming stale bytes.
    sdk/voiceagents/azure-ai-voiceagents/samples/live/sample_live_audio_conversation_async.py:153
  • The callback consumes remaining before checking its sequence against _playback_base. After barge-in advances the base, bytes left from the previous response are still played on the next callback, contradicting the promised immediate drop of pending audio. Track the sequence associated with remaining and discard stale bytes before playback.
    sdk/voiceagents/azure-ai-voiceagents/tests/unit/test_configuration.py:47
  • This test supplies the same v1 value as the default, so it still passes if the override is ignored. Use a non-default sentinel to exercise the behavior named by the test.
    sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_realtime.py:522
  • The hand-written realtime implementation has no deterministic unit coverage for frame serialization/deserialization, typed-event mapping and unknown-event fallback, close/error handling, or resource helpers; the live smoke test covers only one service path. Add mocked WebSocket/session tests for these public behaviors so regressions do not require a gated live environment to detect.
    async def recv(self) -> ServerEvent:

Comment thread sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/_client.py Outdated
Comment thread sdk/voiceagents/azure-ai-voiceagents/azure/ai/voiceagents/aio/_client.py Outdated
@github-actions

This comment has been minimized.

Copilot AI review requested due to automatic review settings August 7, 2026 18:33
@github-actions

This comment has been minimized.

- Fix RST bullet-list continuation-line indentation in VoiceAudioOutputConfig
  (types.py + models/_models.py) and VoiceConversationStatus (models/_enums.py),
  fixing sphinx -W docs build failure (3 docutils warnings -> 0)
- Fix generate_agent single-overload merge + VoiceResponse Optional-narrowing
  (previously fixed, re-dropped by main merge, now re-fixed) -- resolved 4 of 12
  pyright errors
- Fix begin_create_optimization_job/begin_create_generation_job job parameter
  type in _patch_agents.py, _patch_datasets.py, _patch_evaluators.py (+ async):
  was typed as generic JSON alias, but generated base class expects the specific
  _types.<Job> TypedDict -- resolves remaining pyright/mypy arg-type and
  override-incompatible errors
- Re-add all corresponding PostEmitter.ps1 fixes so they survive future regens
- Verified CI-exact clean: pyright 0 errors, mypy (--ignore-missing-imports)
  0 errors, pylint (repo pylintrc) 10.00/10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 59 out of 64 changed files in this pull request and generated no new comments.

Suppressed comments (8)

sdk/ai/azure-ai-projects/PostEmitter.ps1:73

  • The generated method must always return an SSE byte stream, but this replacement honors stream=False. A caller passing stream=False now takes the non-streaming SessionLogEvent deserialization path, contradicting the comment and breaking the sample contract. Consume the caller value to avoid the duplicate keyword, but set _stream to True unconditionally in both generated files.
        if ($inFunc -and $lines[$i] -match '^\s*_stream = (True|kwargs\.pop\(.+\))\s*$') {
            $indent = ([regex]::Match($lines[$i], '^\s*')).Value
            $lines[$i] = $indent + '_stream = kwargs.pop("stream", True)'

sdk/ai/azure-ai-projects/PostEmitter.ps1:33

  • This step does not remove the unusable operation group from the public surface: both operations/__init__.py files still import it and include it in __all__, and api.md still exposes VoiceAgentWebSocketOperations.connect_voice_agent. Remove those exports/mappings as part of this post-generation customization; otherwise users can still import the operation that this block says must not be public.

This issue also appears on line 71 of the same file.

# Remove the generated `voice_agent_web_socket` operation group from the client's public surface
# entirely (import, docstring, and __init__ assignment). The generated operation only performs a
# plain HTTP GET (no WebSocket upgrade handshake) and discards the connection - it's not a usable
# client and was never meant to be public (the real voice-agent WebSocket client is `.realtime`).
$files = 'azure\ai\projects\_client.py', 'azure\ai\projects\aio\_client.py'

sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py:190

  • Bumping _playback_base does not discard the remaining bytes already removed from the queue. The callback emits remaining before checking sequence numbers, so barge-in can continue playing the current buffered chunk despite the stated immediate-stop behavior. Track the sequence associated with remaining (or clear it through thread-safe shared state) when skip_pending_audio() runs.
    sdk/ai/azure-ai-projects/pyproject.toml:48
  • The realtime extra only installs the sync transport. The newly exposed async realtime client lazily imports aiohttp and otherwise raises at connection time, so pip install azure-ai-projects[realtime] does not install everything needed for the feature. Include aiohttp in this extra (the repository's azure-core[aio] convention uses aiohttp>=3.0).
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:182
  • _RESPONSE_TIMEOUT is never applied here: pump() iterates until response.done or an error and can block forever if the service stops producing events without closing the socket. The async counterpart enforces this 45-second limit. Add equivalent bounded receive behavior for the sync path instead of calling pump() without a timeout.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:88
  • The 45-second timeout declared above is never used by this receive loop. If the server neither emits a terminal event nor closes the socket, the sample hangs indefinitely. Apply a bounded receive/turn timeout, as the async live-text sample does.
    sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py:264
  • The public client.realtime surface and its hand-written sync/async WebSocket connection logic are not exercised anywhere under tests/; the added tests only cover HTTP CRUD and header injection. Add unit tests with fake WebSocket transports for URL/query construction, authentication and preview headers, event serialization/deserialization, connection closure, and sync/async error paths before exposing this transport.
    @property
    def realtime(self) -> Realtime:

sdk/ai/azure-ai-projects/.env.template:26

  • The new samples read FOUNDRY_VOICE_MODEL, while this template only defines FOUNDRY_VOICE_MODEL_NAME. Users following the template will have their configured deployment silently ignored and the samples will fall back to gpt-realtime. Add the sample-facing variable as well (the _NAME form is still needed by the test preparer).
FOUNDRY_VOICE_MODEL_NAME=

@github-actions

This comment has been minimized.

…archy)

- VoiceMessageItem class and VoiceConversationItemType enum removed; voice conversation item classes (VoiceSystemMessageItem, VoiceUserMessageItem, VoiceAssistantMessageItem, VoiceFunctionCallItem, VoiceFunctionCallOutputItem, VoiceMcp*Item) now extend the corresponding OpenAI Realtime conversation-item classes directly. VoiceConversationItem is now a Union type alias instead of a model class.

- New RealtimeConversationItem, RealtimeConversationItemMessage(System/User/Assistant), RealtimeConversationItemFunctionCall(Output), RealtimeMCPListTools, RealtimeMCPToolCall, RealtimeMCPApprovalRequest/Response classes and RealtimeConversationItemType enum exposed.

- Reapplied PostEmitter.ps1 fixes that failed to auto-apply this run: docstring indentation for VoiceConversationStatus/VoiceAudioOutputConfig, and VoiceResponse id/conversation_id reportIncompatibleVariableOverride type:ignore.

- Updated tsp-location.yaml.saved to the new commit hash.

Verified: pyright 0 errors, mypy clean, pylint 10.00/10, sphinx docs build succeeds. No sample/test changes needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 59 out of 64 changed files in this pull request and generated 9 comments.

Comment thread sdk/ai/azure-ai-projects/pyproject.toml
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py Outdated
Comment thread sdk/ai/azure-ai-projects/PostEmitter.ps1 Outdated
Comment on lines +181 to +182
conn.response.create()
pump()
Comment on lines +145 to +146
out = remaining[:wanted]
remaining = remaining[wanted:]
Comment on lines +263 to +264
@property
def realtime(self) -> Realtime:
Comment thread sdk/ai/azure-ai-projects/PostEmitter.ps1 Outdated
| Sessions | [Manage hosted sessions](https://learn.microsoft.com/azure/foundry/agents/how-to/manage-hosted-sessions?pivots=python) | `samples/hosted_agents/` |
| Skills (preview) | | `samples/skills/` |
| Toolboxes | [Curate intent-based toolbox in Foundry](https://learn.microsoft.com/azure/foundry/agents/how-to/tools/toolbox?pivots=python) | `samples/hosted_agents/`, `samples/toolboxes/` |
| Voice agents (preview) | [Use the GPT Realtime API for speech and audio](https://learn.microsoft.com/azure/foundry/openai/how-to/realtime-audio) | `samples/agents/voice/` |
@github-actions

Copy link
Copy Markdown
Contributor
[Pilot] PR Pipeline Failure Analysis

What failed

Pipeline: azure-sdk/public build #6732020failed

Check: Pyright static type check for azure-ai-projectsFAIL (exit 1)

Three type errors were found in the new voice agent sample files under sdk/ai/azure-ai-projects/samples/agents/voice/. All three errors are the same pattern: a str value is being passed where bytes is required.

File Line Error
sample_voice_agent_live_audio_conversation_async.py 262:36 Argument of type "str" cannot be assigned to parameter "pcm" of type "bytes" in queue_audio
sample_voice_agent_live_text_conversation.py 166:37 Argument of type "str" cannot be assigned to parameter "pcm" of type "bytes" in play
sample_voice_agent_live_text_conversation_async.py 163:37 Argument of type "str" cannot be assigned to parameter "pcm" of type "bytes" in play

Note: azure-ai-agents pyright check passed (OK).

Relevant pipeline output
2026-08-21 18:36:20,421 [ERROR] azure-sdk-tools: Pyright reported issues:
/mnt/vss/_work/1/s/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py
  ...262:36 - error: Argument of type "str" cannot be assigned to parameter "pcm" of type "bytes" in function "queue_audio"
  "str" is not assignable to "bytes" (reportArgumentType)
/mnt/vss/_work/1/s/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py
  ...166:37 - error: Argument of type "str" cannot be assigned to parameter "pcm" of type "bytes" in function "play"
  "str" is not assignable to "bytes" (reportArgumentType)
/mnt/vss/_work/1/s/sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py
  ...163:37 - error: Argument of type "str" cannot be assigned to parameter "pcm" of type "bytes" in function "play"
  "str" is not assignable to "bytes" (reportArgumentType)
3 errors, 0 warnings, 0 informations

PACKAGE                                      CHECK    STATUS  DURATION(s)
-------------------------------------------------------------------------
/mnt/vss/_work/1/s/sdk/ai/azure-ai-agents    pyright  OK             18.52
/mnt/vss/_work/1/s/sdk/ai/azure-ai-projects  pyright  FAIL(1)        33.07

Recommended next steps

  • In sample_voice_agent_live_audio_conversation_async.py line 262, encode the str argument to bytes before passing it to queue_audio (e.g., value.encode() or use a bytes literal).
  • In sample_voice_agent_live_text_conversation.py line 166 and sample_voice_agent_live_text_conversation_async.py line 163, encode the str argument to bytes before passing it to play.
  • Alternatively, if the pcm parameter should accept both types, update the function signature in the library to Union[str, bytes] or bytes | str.
  • See https://aka.ms/ci-fix

Automated fix: Requested

Generated by Pipeline Analysis Next Steps · 49.2 AIC · ⌖ 6.66 AIC · ⊞ 6K ·

… opt-in, session file IO[bytes] uploads)

- Add foundry_features_query opt-in parameter (_AgentDefinitionOptInKeys.VOICE_AGENTS_V1_PREVIEW) to the voice agent WebSocket connect operation
- Widen AgentsOperations.upload_session_file to accept IO[bytes] in addition to bytes
- Simplify several create/patch body overloads to Union[JSON, IO[bytes]], dropping now-unused typed-dict overloads
- Reword output_modalities docstring
- Bump version to 2.6.0 and update CHANGELOG

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@xitzhang

Copy link
Copy Markdown
Member Author

Copilot resolve the merge conflicts in this pull request

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 58 out of 62 changed files in this pull request and generated 7 comments.

Suppressed comments (7)

sdk/ai/azure-ai-projects/pyproject.toml:48

  • The realtime extra installs only websockets, but async_client.realtime requires aiohttp, which is not a package dependency. A clean azure-ai-projects[realtime] installation therefore supports the sync API but fails when opening an async realtime connection.
    sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py:84
  • If callers provide an immutable headers mapping, this fallback replaces it with a one-entry dictionary and silently drops every caller-supplied header. Preserve the original mapping while adding Accept-Encoding so correlation, conditional, and custom headers still reach the request.
                try:
                    headers[_ACCEPT_ENCODING_HEADER_NAME] = _ACCEPT_ENCODING_IDENTITY_VALUE
                except Exception:  # pylint: disable=broad-except
                    kwargs["headers"] = {_ACCEPT_ENCODING_HEADER_NAME: _ACCEPT_ENCODING_IDENTITY_VALUE}

sdk/ai/azure-ai-projects/PostEmitter.ps1:73

  • This pops the keyword but still honors stream=False, contradicting the stated requirement that this SSE operation must always stream. A caller passing stream=False will restore the buffered-response path and can break the iterator contract; consume the caller value and then set _stream = True unconditionally.
        if ($inFunc -and $lines[$i] -match '^\s*_stream = (True|kwargs\.pop\(.+\))\s*$') {
            $indent = ([regex]::Match($lines[$i], '^\s*')).Value
            $lines[$i] = $indent + '_stream = kwargs.pop("stream", True)'

sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py:146

  • Barge-in does not actually discard a partially consumed chunk: these lines play remaining before consulting any sequence number, while skip_pending_audio() only advances _playback_base. If a delta is larger than one callback buffer, its remainder continues playing after speech starts. Track the sequence associated with remaining (or clear it through a thread-safe signal) before emitting these bytes.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:67
  • _RESPONSE_TIMEOUT is never used: pump() iterates until a terminal event, so a live connection that produces no response.done can block this interactive sample indefinitely despite the documented 45-second limit. Apply the timeout to receive/pump or remove the misleading guarantee.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:56
  • This timeout constant is unused; the subsequent for event in conn has no deadline and can hang forever if the service never emits a final event. Wire the timeout into the sync receive loop rather than advertising a limit that is not enforced.
    sdk/ai/azure-ai-projects/CHANGELOG.md:17
  • The dependency note says websockets is required for both entry points, but the async implementation uses aiohttp. Update this entry together with the realtime extra so the release notes describe both transport dependencies accurately.
* Added an optional dependency on `websockets`, required only when using the new `client.realtime` / `async_client.realtime` voice agent streaming APIs.

Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py Outdated
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py Outdated
Comment thread sdk/ai/azure-ai-projects/CHANGELOG.md Outdated
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py Outdated
…pupr

# Conflicts:
#	sdk/ai/azure-ai-projects/CHANGELOG.md
#	sdk/ai/azure-ai-projects/assets.json

Co-authored-by: xitzhang <11403681+xitzhang@users.noreply.github.com>

Copilot AI commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved the conflicts with main in merge commit c0795de.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 57 out of 61 changed files in this pull request and generated 5 comments.

Suppressed comments (10)

sdk/ai/azure-ai-projects/pyproject.toml:48

  • The realtime extra installs only websockets, but async_client.realtime imports aiohttp and raises at runtime when it is absent (aio/_realtime.py:690-695). Installing the advertised extra therefore does not make the async API usable; include its runtime dependency.
    sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py:84
  • When callers supply an immutable header mapping, this fallback replaces it with a dictionary containing only Accept-Encoding, silently dropping authorization, tracing, and other custom headers. Copy the original mapping before adding the workaround header.
            elif not _has_header_case_insensitive(headers, _ACCEPT_ENCODING_HEADER_NAME):
                try:
                    headers[_ACCEPT_ENCODING_HEADER_NAME] = _ACCEPT_ENCODING_IDENTITY_VALUE
                except Exception:  # pylint: disable=broad-except
                    kwargs["headers"] = {_ACCEPT_ENCODING_HEADER_NAME: _ACCEPT_ENCODING_IDENTITY_VALUE}

sdk/ai/azure-ai-projects/azure/ai/projects/operations/init.py:17

  • This re-exports the generated VoiceAgentWebSocketOperations, even though PostEmitter.ps1:29-32 states that this unusable HTTP implementation must be removed from the public surface in favor of .realtime. Update post-generation customization to remove both this import and its __all__ entry as well.
from ._operations import VoiceAgentWebSocketOperations  # type: ignore

sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/init.py:17

  • The async operations package still publicly exports the generated VoiceAgentWebSocketOperations, contrary to PostEmitter.ps1:29-32, which identifies it as unusable and intended to be removed in favor of .realtime. Remove this import and its __all__ entry through the post-generation customization.
from ._operations import VoiceAgentWebSocketOperations  # type: ignore

sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:153

  • _RESPONSE_TIMEOUT is declared but never applied: pump() iterates indefinitely if the service stalls before response.done, so this interactive sample can hang despite claiming a 45-second timeout. Add timeout support to the sync receive path and enforce it here, matching the async sample.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:88
  • The advertised 45-second response timeout is unused. If the tool call or final response.done never arrives, this loop blocks forever; enforce the timeout through the sync realtime receive API.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py:190
  • remaining is callback-local and is consumed before the queue is checked, while skip_pending_audio() only advances _playback_base. After barge-in, a previously dequeued large chunk can therefore continue playing from remaining even though all queued sequence numbers were invalidated. Track and invalidate the remainder's sequence (or explicitly clear it through thread-safe shared state) when skipping.
    sdk/ai/azure-ai-projects/CHANGELOG.md:10
  • The changelog advertises a connection.item helper, but RealtimeConnection exposes items under connection.conversation.item; following the documented API raises AttributeError. Correct the public usage guidance.
  * Added a new `client.realtime` / `async_client.realtime` entry point for realtime speech-to-speech streaming. Use `with client.realtime.connect(agent_name=...) as connection:` to open a WebSocket connection, `connection.send(...)` to send strongly-typed client events (or use the `connection.response`, `connection.item`, and `connection.session` helpers), and iterate over `connection` to receive strongly-typed server events (`VoiceAgentServerEvent*`, `RealtimeServerEvent*`). The new types `Realtime`, `RealtimeConnection`, and `RealtimeConnectionManager` (and their async equivalents `AsyncRealtime`, `AsyncRealtimeConnection`, `AsyncRealtimeConnectionManager`) are exported from `azure.ai.projects` / `azure.ai.projects.aio`. Requires the optional `websockets` package.

sdk/ai/azure-ai-projects/azure/ai/projects/models/init.py:282

  • PickPropertiesVoiceAudioConfig exposes a TypeSpec utility-generated implementation detail as a public model name. This is not a meaningful customer-facing type; assign the picked shape a deliberate name upstream or suppress it from the generated public exports.
    PickPropertiesVoiceAudioConfig,

sdk/ai/azure-ai-projects/azure/ai/projects/models/init.py:686

  • This adds the private _AgentDefinitionOptInKeys enum to the generated models export list and __all__, turning an underscore-prefixed implementation detail into public API. The realtime implementation already imports it directly from _enums; keep it out of azure.ai.projects.models.
    _AgentDefinitionOptInKeys,

Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/_realtime.py Outdated
Comment thread sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py Outdated
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py Outdated
… insights/Microsoft365 publishing, fix beta operation-group restructure

- Regenerate SDK from azure-rest-api-specs commit 2e1e4f1d8a43ce114b3a3532d25a34fe1c2fa915
  (voice-agent helper-type Voice*->VoiceAgent* rename pass, new agent-insights and
  agents-microsoft365 TypeSpec directories); update tsp-location.yaml.saved accordingly.
- Delete stale types.py (dead TypedDict mirror under generate-typeddict: false that never
  reflected current models); retype its 6 dependent _patch_*.py overloads to use the
  generated JSON alias instead. Automate this deletion in PostEmitter.ps1 going forward.
- Fix recurring _unions.py forward-ref bug for VoiceAgentSessionResponse/Update in
  models/_models.py, now automated as a PostEmitter.ps1 fixup.
- Update _realtime.py/aio/_realtime.py and affected samples/tests for the Voice*->
  VoiceAgent*/Realtime* rename pass and removed message-item classes (now sent as raw dicts).
- Handle agent_endpoint_conversations and voice_agent_web_socket moving from top-level
  client attributes to nested .beta sub-clients upstream, and the new agent_insight_monitors
  beta sub-client:
  - Add agent_endpoint_conversations/agent_insight_monitors to _BETA_OPERATION_FEATURE_HEADERS
    so they get Foundry-Features header injection via the existing generic mechanism.
  - Remove now-dead top-level header-injection code in _patch.py/aio/_patch.py; fix the
    accept-encoding-identity workaround to target the new self.beta location (with a
    hasattr(self, "beta") guard for tests that mock out the generated __init__ - caught by
    running the full test suite).
  - Relocate the voice_agent_web_socket hide-from-public-surface PostEmitter.ps1 fixup.
  - Update 5 samples' client.agent_endpoint_conversations -> client.beta.agent_endpoint_conversations.
  - Update foundry_features_header tests; retire the now-redundant dedicated
    agent_endpoint_conversations header tests in favor of the generic beta-operations
    discovery test, which now covers it (and agent_insight_monitors) automatically.
- Update docs/public-methods.md (cross-checked against runtime reality) and CHANGELOG.md.
- Regenerate api.md/api.metadata.yml.
- Validated: full test suite (826 passed, 105 skipped, 4 pre-existing unrelated failures
  from missing test recordings), plus all 11 voice-agent samples run live end-to-end.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 54 out of 58 changed files in this pull request and generated 7 comments.

Suppressed comments (6)

sdk/ai/azure-ai-projects/pyproject.toml:48

  • The realtime extra does not install aiohttp, although AsyncRealtimeConnectionManager.enter() imports it at runtime. A user installing azure-ai-projects[realtime] can therefore use the sync client but gets a RuntimeError from the advertised async realtime entry point. Include the async transport dependency in this extra.
    sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py:83
  • If a caller supplies an immutable header mapping, this fallback replaces the entire mapping with only Accept-Encoding, silently dropping every caller-provided header. Copy the mapping before adding the forced value so custom headers are preserved.
                except Exception:  # pylint: disable=broad-except
                    kwargs["headers"] = {_ACCEPT_ENCODING_HEADER_NAME: _ACCEPT_ENCODING_IDENTITY_VALUE}

sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:23

  • This sample uses the synchronous realtime WebSocket client, but the installation command omits the realtime extra. In a clean environment it fails with the client's “requires websockets” runtime error before demonstrating the tool flow.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:181
  • The declared 45-second response timeout is never applied: pump() iterates through conn.recv() with no timeout, so a dropped or stalled response can block this interactive sample indefinitely. Expose/use a timeout-capable sync receive path, analogous to the async sample's asyncio.wait_for.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:86
  • _RESPONSE_TIMEOUT is never used, and this iterator waits forever if the service does not emit the expected final event. Apply a bounded receive/iteration timeout so this sample does not hang on a stalled WebSocket response.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py:146
  • A dequeued audio chunk loses its sequence number once its tail is stored in remaining. After skip_pending_audio() advances _playback_base, the callback copies that stale tail into out before checking any sequence, so barge-in can continue playing the old reply. Track the sequence for remaining and discard it when it predates _playback_base.

Comment thread sdk/ai/azure-ai-projects/CHANGELOG.md Outdated
print(f"Agent: {event.transcript}")

while True:
prompt = input("You: ").strip()
Comment on lines +180 to +183
try:
await asyncio.wait_for(pump(), timeout=_RESPONSE_TIMEOUT)
except asyncio.TimeoutError:
print("Timed out waiting for the agent's reply.")

while True:
# input() blocks, so read it off the loop in a worker thread.
prompt = (await asyncio.to_thread(input, "You: ")).strip()
Comment thread sdk/ai/azure-ai-projects/CHANGELOG.md Outdated
Comment on lines +14 to +18
* Added Microsoft 365 agent publishing:
* `project_client.agents.publish_to_microsoft365(agent_name, publish_scope=...)` publishes a Foundry agent to Microsoft 365 / Microsoft Teams and returns a `Microsoft365PublishResult`.
* `project_client.agents.get_microsoft365_publish_defaults(agent_name)` returns default and previously-published values (`Microsoft365PublishDefaults`) used to pre-populate a publish request.
* `project_client.agents.get_microsoft365_package(agent_name)` downloads the Microsoft 365 app package for an agent.
* Added the supporting `Microsoft365PublishScope`, `Microsoft365PermissionScopes`, `ActivityProtocolAccessBoundary`, `PublishApprovalStatus`, and `DigitalWorkerType` enums.
Comment thread sdk/ai/azure-ai-projects/PostEmitter.ps1 Outdated
Xiting Zhang and others added 2 commits September 1, 2026 13:03
…ealtimeConversationItemMessage* classes, fix RecordedTransport.HTTPX2 rename, add voice-agent CRUD recordings

- Regenerated from TypeSpec commit 3fe1059cb3bb4d6dc5cf62910c09c47b64a092ad (purely additive vs prior round)
- Restored RealtimeConversationItemMessageSystem/User/Assistant classes (previously removed upstream,
  now reinstated) to the ConversationItem union in _realtime.py/aio/_realtime.py and 3 samples, replacing
  the raw-dict construction workaround with typed construction
- Fixed RecordedTransport.HTTPX -> HTTPX2 in test_voice_agent_crud.py/_async.py (unrelated shared-tooling
  rename from an upstream merge that broke test collection)
- Updated CHANGELOG.md wording and regenerated api.md/api.metadata.yml
- Updated tsp-location.yaml.saved to the new commit hash (tsp-location.yaml itself is a transient,
  untracked local file used only to drive generation, not committed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Realtime dependencies, public exports, sample correctness, documentation, and test coverage have unresolved issues.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (6)

sdk/ai/azure-ai-projects/pyproject.toml:48

  • The realtime extra installs only websockets, but AsyncRealtimeConnectionManager imports aiohttp and raises at runtime when it is absent. As a result, pip install azure-ai-projects[realtime] does not make the advertised async realtime API usable. Include aiohttp in this extra (and update the changelog wording, which currently says websockets is required for both clients).
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py:73
  • VoiceAgentDefinition.tools accepts VoiceAgentTool instances, but this sample constructs the separate realtime-session model RealtimeFunctionTool and suppresses the resulting type error. Use VoiceAgentFunctionTool here and update the import so the sample demonstrates the supported voice-agent definition API without a list-item ignore.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:126
  • This agent definition uses RealtimeFunctionTool, although VoiceAgentDefinition.tools is typed as list[VoiceAgentTool]; the list-item suppression hides that API mismatch. Replace it with VoiceAgentFunctionTool and update the import so users can copy a type-correct example.
    sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py:258
  • The new hand-written WebSocket client is exposed publicly here, but there are no tests referencing client.realtime, RealtimeConnection, or the corresponding async types. Add mocked sync and async transport tests for URL/header construction, event serialization/deserialization, connection closure, and error paths before publishing this transport surface.
    @property
    def realtime(self) -> Realtime:

sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:68

  • _RESPONSE_TIMEOUT is never used in this synchronous sample: pump() iterates the connection without a deadline, so a stalled or lost response can block the sample indefinitely. Enforce a deadline here (and expose timeout support from RealtimeConnection.recv if needed), as the async variant already does with asyncio.wait_for.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:57
  • This timeout constant is unused, and the subsequent for event in conn has no deadline. If the service never emits the final event, the sample hangs indefinitely. Enforce this deadline here and add timeout support to the synchronous realtime receive path if necessary.
  • Files reviewed: 53/57 changed files
  • Comments generated: 5
  • Review effort level: Balanced

FOUNDRY_PROJECT_ENDPOINT=
FOUNDRY_PROJECT_API_KEY=
FOUNDRY_MODEL_NAME=
FOUNDRY_VOICE_MODEL_NAME=
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py Outdated
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py Outdated
Comment thread sdk/ai/azure-ai-projects/CHANGELOG.md Outdated
Comment on lines +365 to +366
@distributed_trace
def generate_agent(self, body: _models.GenerateVoiceAgentRequest, **kwargs: Any) -> _models.AgentDetails: # type: ignore[override]
… asset gaps

- Fixed genuine bugs found in review: immutable-headers fallback dropping caller
  headers (aio/_patch.py), connection_url query-delimiter corruption, stream=False
  defeating a hard-SSE-only operation (PostEmitter.ps1 + regenerated files),
  audio barge-in not discarding stale buffered chunks, missing aiohttp dependency
  in the [realtime] extra, missing __all__ exports for beta operation classes,
  _AgentDefinitionOptInKeys leaking as public API, wrong tool type in 2 samples
  (RealtimeFunctionTool -> VoiceAgentFunctionTool), 2 samples with interactive
  input() causing EOFError in the non-interactive sample-check runner (added
  to IGNORED_SAMPLES in both copies), unused _RESPONSE_TIMEOUT in 2 samples
  (added real recv(timeout=...) support to the SDK), async sample not
  cancelling the stale server response after a client-side timeout.
- Corrected several stale/inaccurate CHANGELOG.md statements (connection.item ->
  connection.conversation.item, async transport is aiohttp not websockets).
- Added test_generate_agent/_async (recorded) and 37 new transport-mocked unit
  tests across tests/agents/test_realtime_client.py/_async.py covering URL
  construction, auth headers, event serialization/dispatch, timeouts, and
  connection cleanup for the hand-written realtime WebSocket clients.
- Fixed a docs generation (sphinx) failure: two docstrings in models/_models.py
  had un-indented bullet-list continuation lines that docutils flags as
  warnings-as-errors. Fixed directly and via a new PostEmitter.ps1 fixup so
  future regenerations don't reintroduce it.
- Generated, verified, and pushed recordings for the 4 previously-failing
  voice-agent CRUD tests plus 2 new generate_agent tests to azure-sdk-assets;
  updated assets.json's Tag accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

It introduces a breaking module removal, an incomplete credential-origin guard, and unbounded realtime audio scheduling.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

sdk/ai/azure-ai-projects/tsp-location.yaml.saved:2

  • This regeneration pins a spec commit associated with Agent Insights (#45971) and also pulls in Agent Insights and Microsoft 365 API changes, while the PR title mentions only voice agents and the description is still the empty template. Update the description to explain the full generated scope and link every relevant azure-rest-api-specs PR so reviewers can validate the bundled API changes.
  • Files reviewed: 58/62 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment on lines +38 to +40
$typesFile = 'azure\ai\projects\types.py'
if (Test-Path $typesFile) {
Remove-Item $typesFile -Force
Comment on lines +77 to +82
def test_matching_host_does_not_raise(self):
_assert_trusted_connection_url(f"wss://{'my-account.services.ai.azure.com'}/custom/path", _ENDPOINT)

def test_mismatched_host_raises_value_error(self):
with pytest.raises(ValueError):
_assert_trusted_connection_url("wss://evil.example.com/steal-token", _ENDPOINT)
…hony/WebRTC/sub-agent voice features, fix missing preview-header wiring

- Regenerate SDK from azure-rest-api-specs commit 1070c74ae519b6f86540bbd44ea295ff12642e60;
  update tsp-location.yaml.saved accordingly.
- New voice-agent features from this commit (purely additive, no removed/renamed classes):
  - Telephony bindings for Teams Phone/Twilio on �gents.* (create/list/get/update/delete
    binding, list/get/transfer/end call, get/replace transfer targets - 11 new methods).
  - Optional WebRTC transport for realtime sessions (VoiceAgentTransport.WEBRTC) with SDP
    signaling events.
  - New top-level �gent_endpoint_conversations operation group (generated-audio reads),
    distinct from the unchanged �eta.agent_endpoint_conversations.
  - Sub-agent consultation (VoiceAgentDefinition.subagent_config) and conversation_engine
    delegation to a hosted agent.
- list_memories() unbound-variable bug fixed upstream: verified the fix, removed the
  now-obsolete PostEmitter.ps1 fixup (kept an explanatory comment for future regression
  detection).
- Fixed a real functional bug: the new telephony and agent_endpoint_conversations methods
  require the Foundry-Features: VoiceAgents=V1Preview opt-in header per TypeSpec, but had no
  header-injection wiring (would fail with preview_feature_required). Added header injection
  (gated on �llow_preview, matching the existing generate_agent pattern) via 11 new method
  overrides in _patch_agents.py/_patch_agents_async.py and new
  _patch_agent_endpoint_conversations.py/_async.py files for the 2 new conversation methods.
  Also fixed a generator bug where replace_telephony_transfer_targets's 2nd/3rd @overload
  signatures had etag/match_condition types swapped.
- Registered 6 new realtime event types (1 client + 5 server, for RTC signaling and sub-agent
  consultation) in _realtime.py/aio/_realtime.py.
- Added 13 new unit tests in tests/foundry_features_header/ covering the header-injection fix
  for all new methods.
- Added tests/agents/test_voice_agent_telephony.py/_async.py (6 methods) covering telephony
  bindings/calls/transfer-targets and generated-audio not-found paths. Currently skipped: the
  telephony routes are defined in TypeSpec but not yet deployed on the live test service
  (confirmed via empty-body 404s vs a real app-level 404's full JSON error body), and the
  generated-audio not-found path hits the same pre-existing conversation-ID validation quirk as
  the already-documented beta.agent_endpoint_conversations limitation.
- Updated docs/public-methods.md (170->183 methods) and CHANGELOG.md.
- Regenerated api.md/api.metadata.yml.
- Validated: full test suite (1026 passed, 111 skipped, 0 failed) run fresh in one pass, plus
  live e2e validation of 10 of 11 voice-agent samples against the real service, including both
  live-streaming samples (text conversation sync+async, function tool) which exercise realtime
  WebSocket sessions, tool-calling, and conversation persistence/readback end-to-end. Confirmed
  the regeneration is reproducible by re-running tsp-client update + PostEmitter.ps1 from
  scratch and diffing against the working tree (identical result).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Resolve sample-runner hangs, truncated audio frames, missing telephony coverage, and inaccurate WebSocket documentation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

sdk/ai/azure-ai-projects/azure/ai/projects/_realtime.py:786

  • The public documentation says a ws:// override is accepted, but RealtimeConnectionManager.enter() rejects every URL that does not start with wss://. Document this as wss:// only so callers are not promised an option that always raises ValueError.
        :keyword connection_url: Full ``wss://``/``ws://`` URL that overrides the route computed
         from the client endpoint. Query parameters are still appended. Default value is None.

sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py:792

  • The public documentation says a ws:// override is accepted, but AsyncRealtimeConnectionManager.enter() rejects every URL that does not start with wss://. Document this as wss:// only so callers are not promised an option that always raises ValueError.
        :keyword connection_url: Full ``wss://``/``ws://`` URL that overrides the route computed
         from the client endpoint. Query parameters are still appended. Default value is None.
  • Files reviewed: 67/71 changed files
  • Comments generated: 5
  • Review effort level: Balanced

Comment thread eng/tools/azure-sdk-tools/azpysdk/samples.py
Comment thread scripts/devops_tasks/test_run_samples.py
Comment thread sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py
…pupr

Resolved conflicts in azure-ai-projects between this branch's regeneration from
TypeSpec commit 1070c74ae519b6f86540bbd44ea295ff12642e60 (telephony, WebRTC,
sub-agent consultation, generated-audio conversation reads) and main's
independent regeneration/hand-written additions (agent_insight_monitors patch
classes, ShellToolboxTool, WebIQPreviewTool, Hosted Agent session
configuration, routines.create_or_update authorization).

Resolution strategy:
- Fully generated files (_operations.py x2, _models.py, _enums.py,
  models/__init__.py): took this branch's side after verifying, at the class
  and method level, that it is a strict superset of main's content (zero
  classes/methods present on main but absent here).
- Hand-written orchestration files (operations/_patch.py and aio equivalent):
  merged both sides' additions (this branch's AgentEndpointConversationsOperations
  wiring + main's BetaAgentInsightMonitorsOperations wiring); removed a
  resulting duplicate import of BetaAgentInsightMonitorsOperations from the
  generated module now that it's patched.
- CHANGELOG.md: merged both sides' entries; corrected an inaccurate entry
  (the new �uthorization parameter is on .beta.routines.create_or_update,
  not .beta.routines.dispatch as this branch's changelog had said).
- tsp-location.yaml: adopted main's convention of tracking the file directly
  (main had renamed away from the .saved split specifically to avoid
  breaking the release build), keeping this branch's commit
  1070c74ae519b6f86540bbd44ea295ff12642e60.
- api.md/api.metadata.yml: regenerated fresh via �zpysdk apistub . against
  the resolved source rather than hand-merging generated markdown.
- docs/public-methods.md: kept this branch's version; verified method counts
  are still accurate post-merge (no method-set changes from main's patch).
- Fixed two duplicate dict keys (�gent_insight_monitors in both
  models/_patch.py's _BETA_OPERATION_FEATURE_HEADERS and
  foundry_features_header_test_base.py's EXPECTED_FOUNDRY_FEATURES) that
  git's line-based auto-merge introduced silently (both entries had identical
  values, so this was not a functional bug, just redundant code).

Validated: full test suite re-run after resolution (1026 passed, 111 skipped,
0 failed) - identical results to before the merge, confirming no regressions
in either branch's contributions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved moderate issues affect realtime behavior, sample automation, dependencies, API metadata, and telephony coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (7)

eng/tools/azure-sdk-tools/azpysdk/samples.py:92

  • The samples runner recursively executes every Python file not listed here. The two new read-conversation samples require a pre-existing persisted FOUNDRY_VOICE_CONVERSATION_ID and do not create one, so the automated samples check cannot run them reliably. Ignore those two files as well, or make them self-contained.
    "azure-ai-projects": [
        # These interactively read from stdin via input(), which raises EOFError when this
        # runner executes the file non-interactively.
        "sample_voice_agent_live_text_conversation.py",
        "sample_voice_agent_live_text_conversation_async.py",
    ],

scripts/devops_tasks/test_run_samples.py:96

  • Keep this legacy runner's ignore list aligned with the azpysdk runner. It also recursively executes every Python sample, so the two read-conversation samples will fail without a valid pre-existing FOUNDRY_VOICE_CONVERSATION_ID.
    "azure-ai-projects": [
        # These interactively read from stdin via input(), which raises EOFError when this
        # runner executes the file non-interactively.
        "sample_voice_agent_live_text_conversation.py",
        "sample_voice_agent_live_text_conversation_async.py",
    ],

sdk/ai/azure-ai-projects/docs/public-methods.md:63

  • The legend says hand-written methods carry *, and both of these methods are overridden in _patch_agent_endpoint_conversations.py; omitting the markers makes this generated inventory inaccurate.
    sdk/ai/azure-ai-projects/docs/public-methods.md:162
  • begin_create_run is still implemented by the custom BetaAgentInsightMonitorsOperations in operations/_patch_agent_insights.py, so removing its * contradicts this document's hand-written-method legend.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py:82
  • Every test in this new module is skipped, so none of the telephony request serialization, response handling, or generated-audio behavior is exercised in CI. Before merging the new API surface, enable these tests or add transport-mocked coverage that does not depend on undeployed service routes.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py:82
  • The async counterpart is also entirely skipped, leaving the new async telephony and generated-audio paths without executable coverage. Enable these cases or replace them with transport-mocked tests before merging.
    sdk/ai/azure-ai-projects/tsp-location.yaml:2
  • This regeneration advances the TypeSpec commit, but the PR description is still the template and provides no link to the corresponding API-spec change. Please add the source spec PR/commit context so reviewers can validate the generated API against its requirements.
  • Files reviewed: 66/70 changed files
  • Comments generated: 7
  • Review effort level: Balanced

Comment thread sdk/ai/azure-ai-projects/api.metadata.yml Outdated
Comment thread sdk/ai/azure-ai-projects/dev_requirements.txt Outdated
Comment thread sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py Outdated
Comment thread sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py Outdated
Comment thread sdk/ai/azure-ai-projects/tests/agents/test_realtime_client_async.py Outdated
The previous regeneration used a cached wheel in .venv_apistub/.staging
predating some merge-resolution fixes, causing api.md to omit
AgentInsightRunLROPoller/AsyncAgentInsightRunLROPoller and the base class
of BetaAgentInsightMonitorsOperations, even though the actual source was
always correct. Cleared the stale cache and regenerated fresh; verified a
full line-by-line diff against main's api.md now shows zero API elements
present in main but absent here.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved moderate issues affect preview gating, compatibility, sample automation, API metadata, linting, and test coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (10)

eng/tools/azure-sdk-tools/azpysdk/samples.py:91

  • This ignore list is incomplete for the newly added voice samples. The sample runner executes every unlisted *.py; the read-conversation samples require FOUNDRY_VOICE_AGENT_NAME and FOUNDRY_VOICE_CONVERSATION_ID, which no test configuration supplies, and the live-audio sample runs until Ctrl-C when PyAudio is available. Add all three so the automated samples check does not fail or hang.
    "azure-ai-projects": [
        # These interactively read from stdin via input(), which raises EOFError when this
        # runner executes the file non-interactively.
        "sample_voice_agent_live_text_conversation.py",
        "sample_voice_agent_live_text_conversation_async.py",

scripts/devops_tasks/test_run_samples.py:95

  • Keep this legacy sample runner's ignore list aligned with the azpysdk runner. Otherwise it will execute the two read-conversation samples without their required pre-existing IDs, and can run the live-audio sample indefinitely when PyAudio is installed.
    "azure-ai-projects": [
        # These interactively read from stdin via input(), which raises EOFError when this
        # runner executes the file non-interactively.
        "sample_voice_agent_live_text_conversation.py",
        "sample_voice_agent_live_text_conversation_async.py",

sdk/ai/azure-ai-projects/PostEmitter.ps1:40

  • Deleting azure.ai.projects.types removes an existing, non-private import path, so users importing its generated TypedDicts will get ModuleNotFoundError after upgrading. Retain a compatibility module (and deprecate it if needed) or correct its generation rather than removing it silently; this also conflicts with the PR checklist's no-breaking-changes claim.
$typesFile = 'azure\ai\projects\types.py'
if (Test-Path $typesFile) {
    Remove-Item $typesFile -Force

sdk/ai/azure-ai-projects/api.metadata.yml:3

  • This metadata was generated with parser 0.3.30, but the repository pins apiview-stub-generator==0.3.31 in eng/apiview_reqs.txt:18. Regenerate api.md and its metadata with the pinned parser; otherwise the committed parser version/hash will not match the repository's API snapshot tooling.
parserVersion: 0.3.30

sdk/ai/azure-ai-projects/docs/public-methods.md:10

  • The updated claim that this document lists all 183 public methods omits the newly exported realtime API entirely (realtime.connect, connection send/recv/close, and the session/conversation/audio/response helpers). Add that namespace and recalculate the summary so the public-surface inventory matches the API introduced by this PR.
    sdk/ai/azure-ai-projects/docs/public-methods.md:63
  • These methods are implemented by the new hand-written AgentEndpointConversationsOperations subclass, but the document says hand-written methods carry an asterisk. Mark both entries consistently so the API inventory remains accurate.
    sdk/ai/azure-ai-projects/docs/public-methods.md:162
  • Removing the asterisk makes this inventory claim begin_create_run is generated, but it is still overridden in operations/_patch_agent_insights.py:63. Keep the hand-written marker.
    sdk/ai/azure-ai-projects/tests/agents/test_realtime_client.py:28
  • RealtimeServerEventError is never referenced in this test module, so the newly added file introduces an unused-import pylint failure. Remove it from the import list.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py:82
  • All tests in this new telephony/generated-audio module are unconditionally skipped, so these new operation paths receive no request/response or error-handling coverage in CI. Add transport-mocked or recorded coverage that can run without the unavailable service routes instead of committing only disabled placeholders.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py:82
  • All tests in this async telephony/generated-audio module are unconditionally skipped, leaving the new async operation paths unexecuted in CI. Add async transport-mocked or recorded tests that can run independently of deployment availability rather than relying only on header-injection tests.
  • Files reviewed: 66/70 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/_patch.py
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py
…ple/test fixes

Security:
- _assert_trusted_connection_url (sync + async _realtime.py) now compares
  normalized (host, port) tuples with scheme-default-port resolution instead
  of hostname alone, so a connection_url override targeting the same host on
  a different, non-default port (a different origin) is correctly rejected
  instead of receiving the live Authorization token.

Protocol/correctness fixes:
- Async realtime client now passes protocols=("realtime",) to aiohttp's
  ws_connect() instead of a raw Sec-WebSocket-Protocol header, which aiohttp
  never validates/negotiates on its own. Guarded against a caller-kwarg
  collision on "protocols".
- Removed the dead/misleading http:// -> ws:// translation in _to_ws_url
  (both sync and async): enter() unconditionally rejects any non-wss:// URL,
  so that path could never actually be used to connect.
- Live-audio sample (sample_voice_agent_live_audio_conversation_async.py):
  - End-of-stream playback callback branch now pads to the exact frame size
    pyaudio requested instead of returning a short buffer.
  - speech_started no longer calls response.cancel() when no response is
    active (fixes a false-positive service error on the very first user turn).
  - Mic capture callback now bounds concurrent in-flight sends to 1 and drops
    (rather than unboundedly scheduling) frames while a send is still
    in-flight, reporting the dropped-frame count at shutdown.

Test/tooling/doc fixes:
- Added test_voice_samples parametrization (tests/samples/test_samples.py,
  test_samples_async.py) so samples/agents/voice/ is discovered by the
  package's recorded sample tests (previously not wired up at all).
- Added the live-audio sample to IGNORED_SAMPLES in both
  eng/tools/azure-sdk-tools/azpysdk/samples.py and
  scripts/devops_tasks/test_run_samples.py: it runs until Ctrl-C and would
  hang indefinitely under the non-interactive sample-runner.
- Pinned dev_requirements.txt's websockets to >=13.0 to match the realtime
  extra's minimum version.
- Regenerated api.metadata.yml with the pinned apiview-stub-generator==0.3.31
  (was stale at 0.3.30 from a cached build).
- Removed an unused RealtimeServerEventError import in test_realtime_client.py.
- Added regression tests: port-mismatch trusted-connection-url rejection,
  explicit-default-port acceptance, protocols kwarg override, and non-https
  scheme left unchanged in _to_ws_url.

Verified: full test suite passes (1029 passed, 113 skipped, 0 failed).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical sample-runner failures and moderate API/header issues must be resolved before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (8)

Previously missed (1) — in code that hasn't changed since the last review.

sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py:81

  • Routing this new group through _OperationMethodHeaderProxy exposes its immutable-header fallback: if a caller passes a read-only mapping without Foundry-Features, the proxy catches the assignment failure and replaces the mapping with only the preview header, silently dropping all caller headers. Update the proxy fallback to merge {**headers, Foundry-Features: value}; _AcceptEncodingIdentityProxy already demonstrates the preserving behavior.

sdk/ai/azure-ai-projects/CHANGELOG.md:9

  • This describes a standard agent update flow, but AgentsOperations exposes create_version and update_details; there is no agents.update method. Since editing the definition is done by publishing another version, the release note currently directs users to a nonexistent API.
  * Added guided authoring via `project_client.agents.generate_agent(GenerateVoiceAgentRequest(kind=AgentKind.VOICE, ...))`, which returns a service-generated starter definition that can be edited afterward through the standard `create_version`/`update` flow.

sdk/ai/azure-ai-projects/docs/public-methods.md:63

  • These methods are implemented as handwritten overrides in operations/_patch_agent_endpoint_conversations.py, but the document's legend requires handwritten methods to carry *. Without the markers, this inventory incorrectly presents both as generated methods.
    sdk/ai/azure-ai-projects/docs/public-methods.md:162
  • begin_create_run is still implemented by the handwritten _patch_agent_insights.py override, so removing its * makes this inventory contradict its own legend.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py:13
  • The client has no agents.update method, so the documented create_version/update flow is misleading. Voice-agent definitions are changed by creating another immutable version.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_audio_conversation_async.py:32
  • The sample's installation instructions are missing python-dotenv, which is a required direct import on line 53 and is not a package dependency. A clean environment following this command cannot run the sample.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:30
  • The setup command omits python-dotenv, but this sample imports load_dotenv unconditionally. A user following these instructions in a clean environment will fail with ModuleNotFoundError before the sample starts.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py:27
  • The setup command omits python-dotenv, although load_dotenv is imported unconditionally below. Following the documented install command in a clean environment therefore makes the sample fail at startup.
  • Files reviewed: 68/72 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment on lines +87 to +95
"azure-ai-projects": [
# These interactively read from stdin via input(), which raises EOFError when this
# runner executes the file non-interactively.
"sample_voice_agent_live_text_conversation.py",
"sample_voice_agent_live_text_conversation_async.py",
# Runs until Ctrl-C (continuous microphone capture/playback); would hang indefinitely
# under this non-interactive runner whenever PyAudio and live credentials are available.
"sample_voice_agent_live_audio_conversation_async.py",
],
Comment on lines +91 to +99
"azure-ai-projects": [
# These interactively read from stdin via input(), which raises EOFError when this
# runner executes the file non-interactively.
"sample_voice_agent_live_text_conversation.py",
"sample_voice_agent_live_text_conversation_async.py",
# Runs until Ctrl-C (continuous microphone capture/playback); would hang indefinitely
# under this non-interactive runner whenever PyAudio and live credentials are available.
"sample_voice_agent_live_audio_conversation_async.py",
],
… identification fix

- _realtime.py/aio: add User-Agent + x-ms-client-sdk identification (ports fix from
  azure-ai-voicelive PR #48848), with case-insensitive header collision guard so a
  caller-supplied extra_headers User-Agent (any casing) is not duplicated
- test_realtime_client(_async).py: add regression tests for identification headers
  and case-insensitive override behavior
- tests/agents/test_voice_agent_realtime_live(_async).py: new live-only tests for
  voice agent realtime session lifecycle, text-to-audio/transcript turns, and
  function tool-call round trip
- tests/agents/test_voice_agent_conversations(_async).py: new recorded tests for
  beta.agent_endpoint_conversations REST surface, with a live-only setup step to
  obtain a sanitized conversation_id for playback
- assets.json: pin new recordings via test-proxy push (tag ..._d354d861da)
- test-resources.bicep/test-resources-post.ps1/tests.yml: new live-test CI
  infrastructure (Foundry account/project + gpt-realtime model deployment),
  following the azure-ai-voicelive package pattern
- CHANGELOG.md: document the identification fix under Bugs Fixed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Moderate issues remain in live-test provisioning, deployment configuration, and executable test coverage.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (16)

sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic.py:24

  • Voice-agent lifecycle APIs are introduced in 2.6.0, but this command permits 2.0.0. Raise the minimum so the models and operations used by the sample are present.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_basic_async.py:18
  • Voice-agent lifecycle APIs are introduced in 2.6.0, but this command permits 2.0.0. Raise the minimum so the async sample installs a compatible SDK.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_generate.py:20
  • generate_agent for voice agents is added in 2.6.0, so the current minimum can install an SDK that lacks the imported request type and method. Require 2.6.0.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_function_tool.py:23
  • The realtime voice-agent API used by this sample is introduced in 2.6.0, but this command permits 2.0.0. Raise the minimum so client.realtime and the event models are available.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation.py:30
  • The realtime extra and client.realtime API are introduced in 2.6.0, but this command accepts 2.0.0. Users following it can install an older SDK with no realtime namespace; require 2.6.0.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_live_text_conversation_async.py:27
  • The realtime extra and async realtime API are introduced in 2.6.0, but this command accepts 2.0.0. Require 2.6.0 so the documented install includes the APIs used below.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation.py:22
  • The beta voice-conversation operation group is added in 2.6.0, so allowing 2.0.0 makes these instructions install versions without beta.agent_endpoint_conversations. Raise the minimum to 2.6.0.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_read_conversation_audio.py:26
  • The beta voice-conversation audio APIs are added in 2.6.0, so allowing 2.0.0 can install an SDK without these methods. Raise the documented minimum to 2.6.0.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_versions.py:19
  • Voice-agent APIs are introduced in 2.6.0 (CHANGELOG.md:3-17), but this command permits 2.0.0, where VoiceAgentDefinition does not provide this surface. Require 2.6.0 in the setup command.
    sdk/ai/azure-ai-projects/samples/agents/voice/sample_voice_agent_with_tools.py:25
  • Voice-agent APIs are introduced in 2.6.0 (CHANGELOG.md:3-17), but this command permits 2.0.0, where these models are unavailable. Require 2.6.0 so the documented setup installs a compatible SDK.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud.py:33
  • This limitation contradicts the new test_voice_agent_conversations.py, which creates a persisted realtime conversation ID and then reads it through beta.agent_endpoint_conversations. Update this note now that read-back is covered separately.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_crud_async.py:34
  • This limitation contradicts the new async conversation test, which creates a persisted realtime conversation ID and reads it through this REST operation group. Replace the stale service-bug note with a reference to the dedicated coverage.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py:34
  • Every test in this new sync test module is unconditionally skipped, leaving the telephony and generated-audio operation behavior without executable functional coverage; the feature-header tests only validate header injection. Add transport-mocked tests or enable these scenarios before the API is considered covered.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony.py:62
  • This says realtime-generated conversation IDs are rejected, but the new test_voice_agent_conversations.py exercises exactly that setup and read-back path. Update this bullet to point to the dedicated test instead of documenting a conflicting limitation.
    sdk/ai/azure-ai-projects/tests/agents/test_voice_agent_telephony_async.py:34
  • Every test in this new async test module is unconditionally skipped, leaving the async telephony and generated-audio operation behavior without executable functional coverage; the feature-header tests only validate header injection. Add transport-mocked tests or enable these scenarios before the API is considered covered.
    sdk/ai/azure-ai-projects/tsp-location.yaml:2
  • This regeneration pin changes the source specification, but the PR description is still the unfilled template and does not link the corresponding azure-rest-api-specs PR. Replace the template with the voice-agent scope and the source-spec PR so reviewers can validate these generated API changes.
  • Files reviewed: 75/79 changed files
  • Comments generated: 6
  • Review effort level: Balanced

Comment on lines +176 to +178
if (-not $ready) {
Write-Warning "The '$deploymentName' deployment did not finish provisioning in time. Live voice-agent tests may fail until it finishes."
}
TestResourceDirectories:
- ai/azure-ai-projects
EnvVars:
AZURE_TEST_RUN_LIVE: 'true'
agent_name=agent_name,
definition=VoiceAgentDefinition(
model_type=VoiceModelType.MANAGED,
model="gpt-realtime",
agent_name=agent_name,
definition=VoiceAgentDefinition(
model_type=VoiceModelType.MANAGED,
model="gpt-realtime",
Comment on lines +405 to +409
# PR #48484: recording not yet available for these REST-only samples.
"sample_voice_agent_basic.py",
"sample_voice_agent_generate.py",
"sample_voice_agent_versions.py",
"sample_voice_agent_with_tools.py",
Comment on lines +325 to +328
"sample_voice_agent_live_text_conversation_async.py",
"sample_voice_agent_live_audio_conversation_async.py",
# PR #48484: recording not yet available for this REST-only sample.
"sample_voice_agent_basic_async.py",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants