Skip to content

[azure-ai-projects] Add GPT Live WebSocket clients and samples - #49631

Open
xitzhang (xitzhang) wants to merge 18 commits into
xitzhang/gpt-live-generatedfrom
xitzhang/gpt-live-websocket
Open

xitzhang (xitzhang) wants to merge 18 commits into
xitzhang/gpt-live-generatedfrom
xitzhang/gpt-live-websocket

Conversation

@xitzhang

@xitzhang xitzhang (xitzhang) commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

Second PR in the GPT Live stack. Depends on #49629; merge #49629 first.

This PR targets xitzhang/gpt-live-generated so its diff contains only handwritten WebSocket support and associated samples, tests, API reports, and documentation. The parent PR supplies the TypeSpec emission and required tooling pin. This custom-code PR owns model-readback compatibility.

Handwritten support

  • Add beta.voice_agents.live alongside the existing Realtime client, with synchronous and asynchronous clients and matching context-manager behavior.
  • Keep the new SDK implementation to three files: _live.py, _live_utils.py, and aio/_live.py.
  • Reuse the existing authenticated WebSocket transport through private shared bases, preserving Realtime public signatures, credential and initial-URL TLS/same-origin checks, SDK identification, and diagnostic logging.
  • Reuse emitted Live models and discriminator mappings for event serialization/deserialization; retain raw mappings for forward compatibility.
  • Support session controls, text and PCM audio, Responses-delegation function results, cancellation propagation, error handling, and transport/HTTP-session cleanup.
  • Foundry owns startup: wait for session.started, do not send another session.start, and do not negotiate the Realtime subprotocol. Live does not invent a response.cancel command.

Samples and tests

  • Add connection/lifecycle, synchronous/asynchronous headless multi-turn text, actual WAV audio streaming, and Responses function-tool samples.
  • Keep the original single-prompt text default. Multiple quoted prompts reuse one connection and wait for each backend completion.
  • Function results use the canonical call_id from complete response.output_item.done items.
  • Audio completion uses a bounded inactivity heuristic that ignores silent/very-low-level PCM, rejects silence-only replies, and preserves captured PCM in counts and optional WAV output.
  • Add enabled deterministic coverage for typed/raw events, authentication and trust guards, session lifetime, failures, cancellation/concurrency, exact wire shapes, sample sequencing, PCM thresholds, and cleanup.

There are no generated SDK source, TypeSpec pin, or dependency changes in this PR. The handwritten voice-definition readback compatibility hook belongs to this custom-code PR. No runtime dependencies or audio-device tooling are added.

Original implementation validation (before metadata regeneration)

  • 704 targeted offline cases passed, including the parent readback tests, existing Realtime/telemetry regressions, and 87 sample guards. Runtime/unawaited-coroutine warnings were treated as errors. These are pure unit tests run with --noconftest to avoid unrelated recorded-test proxy bootstrap in the sparse validation checkout.
  • SDK Mypy: passed, 60 source files, Python 3.10 target.
  • Live sample Mypy: passed, six modules, using the repository sample-check settings.
  • Repository-pinned Pylint: passed, 10.00/10.
  • Black: passed, 17 handwritten/sample/test files.
  • Clean wheel build and source-content verification: passed.
  • Public API reports match the validated runtime; no private unbound type variables leak into the public methods.

Historical service E2E (before this metadata regeneration)

The runtime and sample source bytes match the implementation exercised against the real configured Foundry project earlier in this session:

  • 7/7 scenarios passed across all five scripts: connection, default sync/async text, two-turn sync/async text, function calling, and concurrent recorded-audio streaming.
  • Connection and audio examples used the existing gpt-live-1 deployment in client-delegation mode. Text/tool examples additionally used an existing gpt-4.1 Responses backend; a second model is optional architecture, not a general Live requirement.
  • Both two-turn examples retained the supplied name across one socket.
  • The real model requested the demonstration weather function, the client returned its explicitly simulated Seattle/72 F result, and the backend continued.
  • Sent 128,400 PCM16 bytes (80,400 spoken WAV bytes plus 48,000 silence bytes), verified by SHA-256.
  • Captured 278,400 bytes of actual returned mono PCM16/24-kHz audio, 5.8 seconds. Transcript: “The largest lake in the world by surface area is the Caspian Sea.”
  • All seven sample-created agent versions were deleted by their samples and independently verified absent with server 404 responses. WebSockets and async HTTP sessions closed; no server errors or recovery cleanup were needed.
  • No recordings or raw audio are stored in this SDK repository. Test Proxy recordings are published separately through the asset pointer. No credentials, private deployment identifiers, pipeline definitions, or infrastructure are committed.

Known boundaries

  • Text examples print Responses backend text, not a frontend speech-finished signal.
  • Live has no speech-finished event; long speech pauses can still split the bounded WAV example's reply.
  • The full existing sample Mypy run has 547 errors in 19 untouched evaluator/workflow sample files. The six Live sample modules pass; unrelated samples were not changed.
  • Live conversation REST operations remain emitted-only, including the known generated last_id/has_more paging limitation.

Stack maintenance

Keep this PR based on xitzhang/gpt-live-generated while #49629 is open. After #49629 merges, retarget/rebase onto the updated feature/azure-ai-projects/vnext as needed and verify the diff before merging.

Metadata regeneration update - 2026-10-23

Merged the updated emitted branch from #49629 normally (no rebase/force push), using
Azure/azure-rest-api-specs#47196 at e30cf6f0dcfbca167edf731d4e48874a63639e8b.

Consumer updates

  • Updated the lifecycle/delegation model references in the Live client and sample guard tests.
  • Added sync/async public-client checks for Foundry-managed ownership across all three lifecycle
    snapshots and delegation creation, including the pinned agent version and exact wire preservation.
  • Documented effective ownership metadata in the existing GPT Live README section.
  • The handwritten parser already uses emitted discriminator mappings, so no additional runtime
    model-conversion patch or public WebSocket signature change was needed.
  • Regenerated paired API reports to resolve the merge's metadata-hash conflict.
  • Generated models, TypeSpec pin and cross-language mapping match the emitted parent exactly;
    they are not duplicated in this PR's diff against its parent branch.
  • Existing microphone/WAV sample behavior and all nine dedicated REST operations are retained.
  • No redirect-policy/security hardening, dependency changes, or live CI pipeline changes are included.

Current validation

  • Combined ordinary pytest run: 679 passed in 26.34 seconds, with live mode disabled.
    This includes Live/Realtime clients, shared transport, 10 generated-model regressions,
    sample/recording-helper guards, and both recorded REST tests.
  • The published Live REST recordings still replay successfully under
    python/ai/azure-ai-projects_6289cbf17e; no recording or asset-pointer update was needed.
  • A separate playback run blocked live fixture creation/cleanup and outbound Python service
    connections while verifying the same recorded HTTP/audio responses.
  • Standard SDK + all-samples Pyright: 0 errors, 0 warnings.
  • SDK Mypy targeting Python 3.10: passed.
  • All 8 Live sample/helper modules pass Mypy with the standard sample-check settings.
  • SDK Pylint: 10.00/10. Edited-test Black checks passed.
  • Paired API metadata hash and the source editable installation were verified.

No new live-service sample run was performed for this metadata-only regeneration; the historical
E2E results above are not being presented as new service validation of this refresh.
This PR keeps its existing ready/non-draft state and its xitzhang/gpt-live-generated target.

Handwritten customization relocation - 2026-10-26

The parent emitted PR #49629 has removed the non-emitted _deserialize_voice hook in commit e8fdf78f48e082d235585999daa305407e4ba53d. This custom-code branch retains the same hook in the existing models/_patch.py, plus its six enabled readback regression cases and bug-fix changelog entry.

The local branch has synced the updated emitted parent using a pending, non-committing merge and retained the customization byte-for-byte. Its source contents are unchanged from the pre-relocation combined SDK; the changed parent makes the customization a child-only diff. This local WebSocket sync has not been committed or pushed, so its publication is still awaiting explicit user approval. The existing remote head remains 069241f86859c5f7e562f0e0835cdab0869a1527.

Validation: 679 tests passed, including the six retained readback cases and both published REST playback tests; SDK/all-samples Pyright 0 errors/warnings, SDK Mypy Python 3.10 passed, Pylint 10/10, Black passed. Generated/public API artifacts and runtime dependencies are unchanged by the relocation. No live-service execution or recording update was needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@xitzhang xitzhang (xitzhang) self-assigned this Oct 20, 2026
@azure-pipelines

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

🟡 Changes recommended

Input-recording overwrite protection, mapping serialization, and concurrent asynchronous cleanup require correction.

3 open issues
What changed in this PR

Adds handwritten GPT Live WebSocket support to Azure AI Projects, building on the generated APIs in #49629, which must merge first.

Changes:

  • Adds synchronous and asynchronous Live clients using shared Realtime transport.
  • Adds lifecycle, multi-turn text, WAV streaming, and function-tool samples with deterministic tests.
  • Updates documentation, public exports, and API reports.

Paths below are relative to sdk/ai/azure-ai-projects/.

File Description
tests/​samples/​test_live_samples.py Adds offline sample guards.
tests/​agents/​test_realtime_client.py Adapts shared-transport identification checks.
tests/​agents/​test_realtime_client_async.py Adapts asynchronous identification checks.
tests/​agents/​test_live_client.py Covers Live protocol and transport behavior.
samples/​agents/​voice/​sample_voice_agent_live_text_conversation.py Demonstrates synchronous multi-turn text.
samples/​agents/​voice/​sample_voice_agent_live_text_conversation_async.py Demonstrates asynchronous multi-turn text.
samples/​agents/​voice/​sample_voice_agent_live_function_tool.py Demonstrates Responses function results.
samples/​agents/​voice/​sample_voice_agent_live_connection.py Demonstrates session lifecycle.
samples/​agents/​voice/​sample_voice_agent_live_audio_conversation_async.py Streams WAV audio and captures replies.
samples/​agents/​voice/​live_sample_utils.py Shares lifecycle and event helpers.
README.md Documents Live usage and limitations.
docs/​public-methods.md Lists the Live entry point.
docs/​GeneratePublicMethodsDoc.ps1 Includes Live in method discovery.
CHANGELOG.md Records Live support and samples.
azure/​ai/​projects/​operations/​_patch.py Exposes synchronous Live operations.
azure/​ai/​projects/​aio/​operations/​_patch.py Exposes asynchronous Live operations.
azure/​ai/​projects/​aio/​_realtime.py Extracts shared asynchronous transport.
azure/​ai/​projects/​aio/​_live.py Implements asynchronous Live support.
azure/​ai/​projects/​_realtime.py Extracts shared synchronous transport.
azure/​ai/​projects/​_live.py Implements synchronous Live support.
azure/​ai/​projects/​_live_utils.py Defines shared Live protocol helpers.
api.metadata.yml Refreshes the API hash.
api.md Reports updated public APIs.

Review effort: Balanced

Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/_live.py Outdated
Comment thread sdk/ai/azure-ai-projects/azure/ai/projects/aio/_realtime.py Outdated
Xiting Zhang and others added 4 commits October 20, 2026 15:46
…t stack

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Validate generated event registry values through a Mapping of objects so Pyright correctly narrows model classes without casts. Add invalid-registry regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add sync and async REST-only samples for stored conversation, item, and recording APIs, with opt-in downloads and deletion. Add 42 enabled offline guards and related documentation. Verified all 18 sync/async REST targets against the real service and 555 focused unit cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Xiting Zhang and others added 5 commits October 21, 2026 12:03
Protect input WAV recordings from hard-linked output aliases, normalize mapping inputs in Live serialization, and await cancellation-safe shared asynchronous transport cleanup. Add deterministic regressions for all three findings while preserving existing close-error behavior. Verified 580 focused unit cases and type/lint/build checks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extend the existing audio sample with optional PyAudio microphone capture and speaker playback, preserving WAV mode. Bound device buffering, surface callback/send errors, report actual audio bytes, and gracefully close the session on Ctrl+C. Add 24 microphone guards and related documentation. Verified 162 focused tests, both CLI modes against the live service, and user-confirmed physical microphone operation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover all nine dedicated Live REST methods in sync and async Test Proxy lifecycles, including pagination, audio content, HTTP statuses, deletion and safe fixture cleanup. Reference the published recording assets and add offline playback regressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Synchronize with TypeSpec e30cf6f0dcfbca167edf731d4e48874a63639e8b. Adapt consumer model references and sample fixtures, verify managed ownership through both public Live clients, refresh paired API reports, and document the effective Foundry delegation owner.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Xiting Zhang and others added 3 commits October 26, 2026 14:38
Consolidate Live samples, remove CLI arguments, use user-temporary audio output, and cover resource ownership and sample conventions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
niuzheng168 pushed a commit to niuzheng168/voice-agent that referenced this pull request Oct 27, 2026
Rebuild the bundled azure-ai-projects 2.10.0 wheel from source on
xitzhang/gpt-live-websocket (c69c028, Azure/azure-sdk-for-python#49631),
which adds beta.voice_agents.live on top of the GPT Live models. The
samples now open audio sessions with project.beta.voice_agents.live
instead of the OpenAI Live SDK, so openai[realtime] is no longer a
requirement; the wheel's [voice] extra brings aiohttp for the client.

The SDK yields generated models for known Live events and dicts for the
unmodeled session.managed_delegation.* events, so event handling uses
mapping access for the type. Offline tests now route the SDK's wss://
Live handshake to a local WebSocket server.

Co-Authored-By: Claude <noreply@anthropic.com>
niuzheng168 pushed a commit to niuzheng168/voice-agent that referenced this pull request Oct 27, 2026
Rebuild the bundled azure-ai-projects 2.10.0 wheel from source on
xitzhang/gpt-live-websocket (c69c028, Azure/azure-sdk-for-python#49631),
which adds beta.voice_agents.live on top of the GPT Live models. The
samples now open audio sessions with project.beta.voice_agents.live
instead of the OpenAI Live SDK, so openai[realtime] is no longer a
requirement; the wheel's [voice] extra brings aiohttp for the client.

The SDK yields generated models for known Live events and dicts for the
unmodeled session.managed_delegation.* events, so event handling uses
mapping access for the type. Offline tests now route the SDK's wss://
Live handshake to a local WebSocket server.

Co-Authored-By: Claude <noreply@anthropic.com>
niuzheng168 pushed a commit to niuzheng168/voice-agent that referenced this pull request Oct 27, 2026
Rebuild the bundled azure-ai-projects 2.10.0 wheel from source on
xitzhang/gpt-live-websocket (c69c028, Azure/azure-sdk-for-python#49631),
which adds beta.voice_agents.live on top of the GPT Live models. The
samples now open audio sessions with project.beta.voice_agents.live
instead of the OpenAI Live SDK, so openai[realtime] is no longer a
requirement; the wheel's [voice] extra brings aiohttp for the client.

The SDK yields generated models for known Live events and dicts for the
unmodeled session.managed_delegation.* events, so event handling uses
mapping access for the type. Offline tests now route the SDK's wss://
Live handshake to a local WebSocket server.
Comment thread sdk/ai/azure-ai-projects/tests/samples/test_live_samples.py Outdated
Comment thread sdk/ai/azure-ai-projects/tests/samples/test_live_samples.py Outdated
Xiting Zhang and others added 2 commits October 27, 2026 13:56
Create and clean up a stored greeting conversation when no existing ID is supplied. Preserve read-only behavior for supplied IDs and remove source-shape and filename assertions per review while retaining behavioral coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reuse the existing REST fixture for success and failure cleanup checks. Remove the simulated greeting, clock, and persistence test setup without changing the sample.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
szhaomsft pushed a commit to microsoft/voice-agent that referenced this pull request Oct 28, 2026
…S sample (#72)

* Use the preview Projects SDK for GPT Live agent lifecycle

The GPT Live samples now define agents with the azure-ai-projects
VoiceAgentLiveDefinition and PromptAgentDefinition models and create,
read back, and delete them through AIProjectClient.agents instead of
raw httpx REST calls. Audio still uses the OpenAI Live SDK because the
preview build has no Live WebSocket client.

The GPT Live models are not on PyPI yet, so bundle the unmodified
azure_ai_projects-2.10.0 wheel from azure-sdk build 6995855
(Azure/azure-sdk-for-python#49629) in dist/ and install it from the
gpt_live requirements. dist/README.md records its source and SHA-256.

Offline lifecycle tests now drive the real SDK client against an
in-memory transport and also cover response_delegation.py.

* Stream GPT Live audio with the Projects SDK Live client

Rebuild the bundled azure-ai-projects 2.10.0 wheel from source on
xitzhang/gpt-live-websocket (c69c028, Azure/azure-sdk-for-python#49631),
which adds beta.voice_agents.live on top of the GPT Live models. The
samples now open audio sessions with project.beta.voice_agents.live
instead of the OpenAI Live SDK, so openai[realtime] is no longer a
requirement; the wheel's [voice] extra brings aiohttp for the client.

The SDK yields generated models for known Live events and dicts for the
unmodeled session.managed_delegation.* events, so event handling uses
mapping access for the type. Offline tests now route the SDK's wss://
Live handshake to a local WebSocket server.

* Drop session.managed_delegation.* handling from GPT Live samples

The service no longer emits session.managed_delegation.* events. For
foundry_managed_agent delegation it sends session.delegation.created,
the prompt agent's Responses stream as response.event with that
delegation ID, and session.commentary/thinking.appended when Foundry
forwards an accepted section to GPT Live.

The Delegation pane now shows managed backend status and raw tagged-text
output from response.event, and marks the latest delegation when Foundry
acknowledges forwarding. Managed backend failures stay visible without
ending the session. ManagedToolHandler no longer waits for the removed
completion events.

* Add JavaScript GPT Live samples with the preview Projects SDK

Add samples/gpt_live_js: Node.js versions of the GPT Live Responses and
managed prompt-agent delegation samples. Agents are created, read back,
and deleted with AIProjectClient.agents, and audio streams through
project.beta.voiceAgents.live. Node has no built-in audio devices, so
the samples stream a recorded PCM16/24 kHz WAV question in real time
and can save the spoken reply.

The JS SDK's GPT Live client is not released and its pull request has
no CI build, so bundle a local Node ESM build of @azure/ai-projects
2.10.0 from Azure/azure-sdk-for-js#40419 (4201af1) in dist/, recorded
in dist/README.md. Managed delegation follows the current service:
session.delegation.created, response.event lifecycle, and
session.commentary.appended, with no session.managed_delegation.*.

Offline node:test tests drive the real SDK client with an in-memory
HTTP client and a scripted Live WebSocket transport.

* Split GPT Live samples into python/ and a browser js/ sample

Move the Python GPT Live samples into samples/gpt_live/python and keep a
shared samples/gpt_live/.env for both languages; update the downloader
path, the realtime_stt audio import, and the READMEs.

Replace the WAV-based JavaScript CLI samples with samples/gpt_live/js, a
simple browser sample with microphone input. A Node.js server creates or
reuses the agents with the preview @azure/ai-projects package (Responses
delegation by default, --managed for a pinned prompt agent), serves the
page, and relays each page's microphone audio to a GPT Live session
through project.beta.voiceAgents.live. The page captures 24 kHz PCM16
with an AudioWorklet, plays the teacher's audio, and shows GPT Live,
Delegation, and You panes. The credential stays on the server, which
listens on 127.0.0.1 and accepts Live connections only from its page.

Offline node:test tests cover agent setup, the relay, and the HTTP
surface with the real SDK client.

* Add a Voice Agent structured-input sample

Add samples/voice_agent_with_structured_input.py with its guide and an
example input file: declare structured inputs with
StructuredInputDefinition, reference them in the saved instructions with
Handlebars placeholders, and pass per-session values through the Projects
SDK's structured_inputs argument (or the x-ms-voice-structured-inputs
header for deployments that reject the query parameter). Offline tests in
tests/test_structured_input.py use the real SDK client.

* Add MCP and local function tools to the browser sample's managed mode

npm run managed now mirrors prompt_agent_delegation_tools.py: the prompt
agent gets the public MCP calculator (add only) and a local
get_current_datetime function, and the GPT Live agent is told to delegate
addition and date/time questions. The server collects completed
function calls from response.event, waits for response.completed, sends
each function_call_output with response.item.create, then one
response.create to resume the managed delegation.

This preview JS SDK refuses response.item.create and response.create
unless the session uses Responses delegation, and doesn't export its Node
transport. live_transport.mjs therefore opens each session with
VoiceAgentLiveClient over a small ws transport passed through the public
webSocketFactory option, and sends those two commands on it directly;
everything else still goes through the SDK.

Verified live on voice-live-tip: the MCP calculator answered 17 + 25, and
the local function's time (with its IANA timezone) was spoken back.

* Connect the browser sample to GPT Live directly instead of relaying

The page now opens the agent's Live WebSocket itself with the SDK's
VoiceAgentLiveClient, bundled for the browser with esbuild. The local
server no longer relays audio or Live events: it creates the agents,
serves the page, and returns an access token from az login on
POST /token, only to its own page (Host and Origin checks).

Browsers cannot set handshake headers, so the page's transport offers
the "live" and "authorization.bearer.<token>" subprotocols, which
Foundry promotes to an Authorization header and answers with "live",
and uses api-version=2025-11-15-preview in place of the
Foundry-Features header. The managed tools' local date/time function
now runs in the page and still returns its results with
response.item.create and response.create on the same socket.

---------

Co-authored-by: Zheng Niu <zhn@microsoft.com>
Xiting Zhang and others added 3 commits October 28, 2026 17:21
Clarify Realtime and GPT Live setup, sample choices, and client descriptions without changing runtime behavior, public APIs, generated code, or tests.

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants