[BREAKING] Python: fix OpenAI Azure routing and provider samples#4925
[BREAKING] Python: fix OpenAI Azure routing and provider samples#4925eavanvalkenburg wants to merge 23 commits intomicrosoft:mainfrom
Conversation
cf47d1b to
c056990
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates Python OpenAI client routing so that generic OpenAI usage stays on OpenAI when OPENAI_API_KEY is configured (even if AZURE_OPENAI_* variables are present), and refreshes samples/docs/tests to match the current client lineup and explicit Azure credential-based patterns.
Changes:
- Refactors shared OpenAI/Azure settings resolution to implement the new routing precedence and support explicit
credential-based Azure routing. - Refreshes provider samples/READMEs (OpenAI + Azure) to use
OpenAIChatClient/OpenAIChatCompletionClient, adding new sample files and removing deprecated Assistants samples. - Updates Azure-focused tests and fixtures to use explicit credential routing and deployment-specific env vars.
Reviewed changes
Copilot reviewed 56 out of 60 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| python/samples/README.md | Documents routing precedence for generic OpenAI clients in samples landing page. |
| python/samples/02-agents/providers/openai/openai_responses_client_basic.py | Removes legacy sample in favor of current client samples. |
| python/samples/02-agents/providers/openai/openai_assistants_with_session.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_with_response_format.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_with_function_tools.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_with_file_search.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_with_explicit_settings.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_with_existing_assistant.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_with_code_interpreter.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_provider_methods.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/openai_assistants_basic.py | Removes deprecated Assistants provider sample. |
| python/samples/02-agents/providers/openai/client_with_web_search.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_structured_output.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_shell.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_session.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_runtime_json_schema.py | Updates sample construction for OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_local_shell.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_local_mcp.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_hosted_mcp.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_code_interpreter_files.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_code_interpreter.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_agent_as_tool.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_streaming_image_generation.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_reasoning.py | Switches sample to OpenAIChatClient and aligns option types. |
| python/samples/02-agents/providers/openai/client_image_generation.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_image_analysis.py | Switches sample to OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_basic.py | Updates basic OpenAI sample to use explicit model/key parameters. |
| python/samples/02-agents/providers/openai/chat_completion_client_with_web_search.py | Switches sample to OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/openai/chat_completion_client_with_session.py | Switches sample to OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/openai/chat_completion_client_with_runtime_json_schema.py | Switches runtime-schema sample to OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/openai/chat_completion_client_with_local_mcp.py | Switches MCP sample to OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/openai/chat_completion_client_with_function_tools.py | Switches tools sample to OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/openai/chat_completion_client_with_explicit_settings.py | Updates explicit settings sample for OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/openai/chat_completion_client_basic.py | Adds a new basic Chat Completions sample. |
| python/samples/02-agents/providers/openai/client_with_function_tools.py | Adds a new function-tools sample for OpenAIChatClient. |
| python/samples/02-agents/providers/openai/client_with_explicit_settings.py | Adds a new explicit-settings sample for OpenAIChatClient. |
| python/samples/02-agents/providers/openai/README.md | Rewrites OpenAI provider sample index to match current client split and routing guidance. |
| python/samples/02-agents/providers/custom/README.md | Updates raw/public client names in custom provider docs. |
| python/samples/02-agents/providers/azure/openai_client_with_structured_output.py | Adds Azure-backed structured output sample using generic OpenAIChatClient + credential. |
| python/samples/02-agents/providers/azure/openai_client_with_session.py | Adds Azure-backed session management sample for OpenAIChatClient. |
| python/samples/02-agents/providers/azure/openai_client_with_function_tools.py | Adds Azure-backed tools sample for OpenAIChatClient. |
| python/samples/02-agents/providers/azure/openai_client_basic.py | Adds Azure-backed basic sample for OpenAIChatClient. |
| python/samples/02-agents/providers/azure/openai_chat_completion_client_with_session.py | Adds Azure-backed session sample for OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/azure/openai_chat_completion_client_with_function_tools.py | Adds Azure-backed tools sample for OpenAIChatCompletionClient. |
| python/samples/02-agents/providers/azure/openai_chat_completion_client_with_explicit_settings.py | Updates Azure explicit-settings sample; now uses azure_endpoint parameter. |
| python/samples/02-agents/providers/azure/openai_chat_completion_client_basic.py | Updates Azure basic sample to use explicit env-based Azure settings. |
| python/samples/02-agents/providers/azure/README.md | Expands Azure provider docs with sample index + required env vars + azure-identity note. |
| python/packages/openai/tests/openai/test_openai_chat_completion_client_azure.py | Updates Azure routing tests for OpenAIChatCompletionClient (credential routing + new env vars). |
| python/packages/openai/tests/openai/test_openai_chat_completion_client.py | Aligns expected exception type to SettingNotFoundError. |
| python/packages/openai/tests/openai/test_openai_chat_client_azure.py | Updates Azure routing tests for OpenAIChatClient (credential routing + new env vars). |
| python/packages/openai/tests/openai/test_openai_chat_client.py | Aligns expected exception type to SettingNotFoundError. |
| python/packages/openai/tests/openai/conftest.py | Adds Azure deployment-specific env vars to fixtures. |
| python/packages/openai/agent_framework_openai/_shared.py | Implements the shared routing precedence and Azure credential/token-provider handling. |
| python/packages/openai/agent_framework_openai/_chat_completion_client.py | Reworks constructors/docstrings to use shared routing helper + adds credential support. |
| python/packages/openai/agent_framework_openai/_chat_client.py | Reworks constructors/docstrings to use shared routing helper + adds credential support. |
| python/packages/openai/README.md | Adds short routing precedence note for mixed OpenAI/Azure envs. |
| python/packages/openai/AGENTS.md | Documents routing precedence for maintainers/contributors. |
| python/packages/azure-ai/agent_framework_azure_ai/_deprecated_azure_openai.py | Preserves deprecated wrapper behavior by temporarily preferring one Azure env var. |
| python/README.md | Documents routing precedence at the Python package level. |
Comments suppressed due to low confidence (1)
python/samples/02-agents/providers/azure/openai_chat_completion_client_with_explicit_settings.py:22
- Minor grammar: “This samples connects to Azure OpenAI.” → “This sample connects to Azure OpenAI.”
python/packages/azure-ai/agent_framework_azure_ai/_deprecated_azure_openai.py
Outdated
Show resolved
Hide resolved
moonbox3
left a comment
There was a problem hiding this comment.
Automated Code Review
Reviewers: 3 | Confidence: 82%
✓ Security Reliability
This PR refactors the generic OpenAI clients to support both OpenAI and Azure OpenAI routing with a clear precedence order (explicit Azure inputs > OPENAI_API_KEY > Azure env fallback). The core routing logic in
_shared.pyis well-structured. The main security/reliability concern is the_prefer_single_azure_endpoint_envcontext manager in the deprecated Azure wrappers, which mutatesos.environand is not thread-safe — concurrent client construction could observe incorrect environment state. Additionally, theload_openai_service_settingsfunction has a code path where a passedclientbypasses credential/model validation, which could lead to runtime failures. The credential resolution and token scope handling are correct. No secrets are hardcoded beyond the well-known Azure cognitive services scope (appropriately annotated). Test changes are consistent with the new routing behavior.
✓ Test Coverage
This PR significantly refactors the OpenAI client routing logic to support a three-tier precedence (explicit Azure inputs → OpenAI API key → Azure env fallback) and adds a
credentialparameter for Azure auth. Test coverage for the main routing paths is reasonable: each client type (chat, chat completions, embedding) has tests for Azure auto-detection, OpenAI-wins-over-Azure precedence, explicit-credential-wins-over-OpenAI precedence, and AsyncTokenCredential wrapping. However, several new code paths in_resolve_azure_credential_to_token_providerandload_openai_service_settingslack corresponding test cases, particularly: syncTokenCredentialhandling, theModuleNotFoundErrorpath when azure-identity is absent, theValueErrorwhen neither API key nor credential is provided for Azure routing, and the missing deployment name error path.
✗ Design Approach
The PR centralizes OpenAI/Azure routing into
load_openai_service_settingsand adds first-classcredentialsupport. The documentation, test, and sample changes are well-structured. Two design-level issues stand out: (1) the_prefer_single_azure_endpoint_envcontext manager in the deprecated Azure wrappers mutatesos.environglobally—this is not thread-safe and is the wrong abstraction layer; the deprecated classes already build theirasync_clientexplicitly, so they should pass that constructed client tosuper().__init__(async_client=...)instead of manipulating the process environment to suppress env var conflicts; (2) treatingapi_versionalone as an unambiguous Azure routing signal inload_openai_service_settingsis fragile—a caller who passesapi_versionwithout an endpoint (and withoutAZURE_OPENAI_ENDPOINTin env) gets a confusing settings error about a missing endpoint rather than the intended Azure routing.
Automated review by moonbox3's agents
python/packages/openai/tests/openai/test_openai_embedding_client_azure.py
Show resolved
Hide resolved
67c731c to
c6fde38
Compare
python/samples/02-agents/providers/openai/chat_completion_client_basic.py
Show resolved
Hide resolved
e424305 to
846b996
Compare
Prefer OpenAI when OPENAI_API_KEY is present unless Azure is explicitly requested. Clarify constructor docs, keep deprecated Azure wrappers compatible with stricter settings validation, and refresh the provider samples and tests to use the current client patterns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extend the shared OpenAI-vs-Azure routing and credential behavior to the embedding client, add Azure embedding regression coverage, and refresh the embedding samples to use the generic client path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
846b996 to
64642e9
Compare
Motivation and Context
This change fixes mixed OpenAI/Azure routing for the Python OpenAI clients so generic OpenAI usage does not accidentally switch to Azure just because Azure environment variables are present. It also refreshes the provider and embedding samples/docs to match the current client lineup and explicit Azure credential-based patterns, while preserving compatibility in the deprecated Azure OpenAI wrappers.
Description
Contribution Checklist