Add opt-in unified API mode for prompt voice agents - #9634
Conversation
|
Azure Pipelines: Successfully started running 1 pipeline(s). 20 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Azure Pipelines: Successfully started running 1 pipeline(s). 20 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Adds opt-in unified API deployment modes for prompt voice agents while retaining legacy behavior.
Changes:
- Adds legacy, unified, and unified-flat deployment modes.
- Supports unified create/update, version persistence, and WebSocket endpoints.
- Adds flat voice payload models, documentation, and tests.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents voice API modes and behavior. |
service_target_agent.go |
Implements mode selection, deployment, and persistence. |
service_target_agent_test.go |
Tests mode resolution and endpoints. |
agent_yaml/map.go |
Builds flat voice payloads. |
agent_yaml/map_voice_test.go |
Tests flat voice mapping. |
agent_api/operations.go |
Adds unified API operations. |
agent_api/operations_test.go |
Tests unified routes and headers. |
agent_api/models.go |
Defines flat voice models. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (3)
cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_yaml/map_voice_test.go:250
- [azd-code-reviewer] These unchecked assertions can panic when the generated wire shape changes, hiding which field is malformed. Guard each decoded JSON level so the test fails with a localized diagnostic instead.
definition := wire["definition"].(map[string]any)
audio := definition["audio"].(map[string]any)
output := audio["output"].(map[string]any)
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go:2334
- [azd-code-reviewer] The new create/update decision tree is not covered by the added tests. The client tests verify each HTTP method in isolation, but they would not catch regressions where a 404 updates, a 200 creates, or a non-404 GET error is ignored. Add orchestration tests for successful GET, 404, and another error status, asserting which follow-up request is issued.
remoteAgent, getErr := agentClient.GetVoiceAgentUnified(
ctx, request.Name, agent_api.AgentEndpointAPIVersion, overriddenHost,
)
if getErr == nil && remoteAgent != nil {
progress("Updating voice agent using unified API")
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go:2186
- [azd-code-reviewer] This new
os.Getenvinput is missing from the canonical environment-variable reference.cli/azd/docs/environment-variables.mdis the source of truth and already has anazure.ai.agentssection; addAZURE_VOICE_AGENT_APIthere with its accepted values, precedence, and legacy default so the README and reference do not drift.
mode = strings.TrimSpace(os.Getenv(voiceAgentAPIEnvKey))
Travis Angevine (trangevi)
left a comment
There was a problem hiding this comment.
What is the timeline of this in the backend? I really don't like having all of this backcompat support for something that's still private preview and clearly in flux. If the backend is actively rolling out, then we should wait for that to complete and just make the full switch.
…ice-agent-unified-api # Conflicts: # cli/azd/extensions/azure.ai.agents/README.md
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (2)
cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_yaml/map_voice_test.go:250
- azd-code-reviewer: These unchecked assertions turn an unexpected serialized shape into a package-stopping panic instead of a useful test failure. Guard each lookup and type assertion before descending into the next map.
definition := wire["definition"].(map[string]any)
audio := definition["audio"].(map[string]any)
output := audio["output"].(map[string]any)
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go:2334
- azd-code-reviewer: The core 200-vs-404 dispatch is not exercised by automated tests. The added client tests verify each HTTP method independently, so a regression that selects update after a 404, creates after a 200, or mutates after another GET failure would still pass. Add table-driven coverage around this branch for 200, 404, and non-404 failures.
remoteAgent, getErr := agentClient.GetVoiceAgentUnified(
ctx, request.Name, agent_api.AgentEndpointAPIVersion, overriddenHost,
)
if getErr == nil && remoteAgent != nil {
progress("Updating voice agent using unified API")
|
Thanks for the review. I removed the prompt voice API mode details from the public README for now; we'll add public docs when the prompt voice flag is removed. I also created follow-up #9681 to remove the temporary legacy API integration after unified API rollout stabilizes, and updated #9654 to track restoring the docs later.\n\nFor the temporary backcompat: service rollout is still in progress, the service team confirmed the existing /voice_agents API will remain supported for a transition period, and azd needs to line up with the end-of-month public preview timeline. This PR keeps legacy as the default while enabling private regression against the new /agents path; once rollout is stable we can switch the default and remove the compatibility modes via #9681. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Suppressed comments (4)
cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_yaml/map_voice_test.go:250
- azd-code-reviewer: These unchecked assertions can panic and abort the package when the marshaled wire shape regresses, hiding which JSON level was malformed. Guard each decoded map assertion so the test reports a normal, localized failure.
definition := wire["definition"].(map[string]any)
audio := definition["audio"].(map[string]any)
output := audio["output"].(map[string]any)
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go:2272
- azd-code-reviewer: Persisting a unified voice version makes the existing contract comments stale:
service_target_agent.go:554-556says every prompt-voice deploy has no version and records only NAME+ENDPOINT, andinternal/cmd/doctor/checks_agent_status.go:705-709makes the same assumption. Update them to distinguish legacy from unified mode; otherwise future changes may incorrectly treat the new VERSION as impossible.
if apiMode != voiceAgentAPIModeLegacy {
versionValue = agentObject.Versions.Latest.Version
cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go:2173
- azd-code-reviewer:
AZURE_VOICE_AGENT_APIis a new user-facing opt-in switch, but a repository-wide search finds no documentation for it outside the implementation. Add it to the extension documentation with the default, accepted values, regional/preview limitations, and precedence between azd environment values and the process environment; otherwise users cannot discover or safely configure the mode after this PR description is gone.
This issue also appears on line 2271 of the same file.
const voiceAgentAPIEnvKey = "AZURE_VOICE_AGENT_API"
cli/azd/extensions/azure.ai.agents/internal/cmd/nextstep/state.go:833
- azd-code-reviewer: This changes
ServiceState.IsDeployedso prompt-voice services are marked deployed fromAGENT_<KEY>_ENDPOINT, but its contract ininternal/cmd/nextstep/types.go:229-234still states that deployment always requires a non-empty VERSION. Update that documentation to describe the voice endpoint exception so callers do not rely on the old invariant.
// Voice deploys use the base ENDPOINT env var as the completion marker. The
// legacy voice API does not produce AGENT_<KEY>_VERSION, and unified voice
// deploys write VERSION before ENDPOINT to keep ENDPOINT as the final marker.
// Require ENDPOINT for voice even when VERSION is present, otherwise a partial
// env write could be reported as deployed before the callable endpoint was
Summary
AZURE_VOICE_AGENT_APImode for prompt voice agents so azd can deploy through the unified/agentsAPI while keeping legacy/voice_agentsas the default.legacy,unified, andunified-flatmodes to cover current regional rollout and West US 2 TiP/spec validation.wss://.../endpoint/protocols/voice?api-version=v1endpoints.Why
/voice_agentsAPI and object-shapedaudio.output.voicepayload./agentsAPI and the newer flataudio.output.voiceshape from the latest REST spec.Validation
go test ./... -count=1go build ./...cspell lint 'extensions/**/*.go' 'extensions/**/*.md' --config ./.vscode/cspell.yaml --no-progressAZURE_VOICE_AGENT_API=unified-flat: provision, deploy, repeat deploy via remote GET + unified update path, GET assertion for flat output shape, persistedAGENT_<SERVICE>_VERSION, andwss://.../agents/{name}/endpoint/protocols/voice?api-version=v1endpoint.AZURE_VOICE_AGENT_API=unified-flat: managed agent init/provision/deploy, BYOM realtime and BYOM cascaded model deployments, BYOM service init/deploy, unified/agents/{name}control-plane GET assertions for managed/self_deployed model types and flat output shape, same-agent redeploy through unified update path, and voice endpoint route smoke (400expected for non-WebSocket GET).legacymode and/voice_agents, thenAZURE_VOICE_AGENT_API=unified-flatredeployed the same agent through/agents/{name}update and returned flat output shape.AZURE_VOICE_AGENT_API: managed, BYOM realtime, and BYOM cascaded all deployed through/voice_agents; endpoints remained legacyhttps://.../voice_agents/{name}markers andAGENT_<SERVICE>_VERSIONwas cleared/empty.Fixes #9654