Skip to content

[BREAKING] Python: fix OpenAI Azure routing and provider samples#4925

Open
eavanvalkenburg wants to merge 23 commits intomicrosoft:mainfrom
eavanvalkenburg:openai_fix_client_setup
Open

[BREAKING] Python: fix OpenAI Azure routing and provider samples#4925
eavanvalkenburg wants to merge 23 commits intomicrosoft:mainfrom
eavanvalkenburg:openai_fix_client_setup

Conversation

@eavanvalkenburg
Copy link
Member

@eavanvalkenburg eavanvalkenburg commented Mar 26, 2026

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

  • update the shared OpenAI routing precedence and constructor documentation across the raw and public chat and embedding clients
  • preserve deprecated Azure OpenAI wrapper behavior when both Azure endpoint and base URL settings are present
  • refresh OpenAI and Azure provider/embedding samples and READMEs to use the current client names and explicit configuration patterns
  • update Azure-focused chat and embedding tests to use explicit credential-based Azure routing and provider-specific deployment environment variables

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

Copilot AI review requested due to automatic review settings March 26, 2026 10:02
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation python labels Mar 26, 2026
@eavanvalkenburg eavanvalkenburg changed the title Python: fix OpenAI Azure routing and provider samples [BREAKING] Python: fix OpenAI Azure routing and provider samples Mar 26, 2026
@eavanvalkenburg eavanvalkenburg force-pushed the openai_fix_client_setup branch from cf47d1b to c056990 Compare March 26, 2026 10:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.”

Copy link
Contributor

@moonbox3 moonbox3 left a comment

Choose a reason for hiding this comment

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

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.py is well-structured. The main security/reliability concern is the _prefer_single_azure_endpoint_env context manager in the deprecated Azure wrappers, which mutates os.environ and is not thread-safe — concurrent client construction could observe incorrect environment state. Additionally, the load_openai_service_settings function has a code path where a passed client bypasses 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 credential parameter 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_provider and load_openai_service_settings lack corresponding test cases, particularly: sync TokenCredential handling, the ModuleNotFoundError path when azure-identity is absent, the ValueError when 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_settings and adds first-class credential support. The documentation, test, and sample changes are well-structured. Two design-level issues stand out: (1) the _prefer_single_azure_endpoint_env context manager in the deprecated Azure wrappers mutates os.environ globally—this is not thread-safe and is the wrong abstraction layer; the deprecated classes already build their async_client explicitly, so they should pass that constructed client to super().__init__(async_client=...) instead of manipulating the process environment to suppress env var conflicts; (2) treating api_version alone as an unambiguous Azure routing signal in load_openai_service_settings is fragile—a caller who passes api_version without an endpoint (and without AZURE_OPENAI_ENDPOINT in env) gets a confusing settings error about a missing endpoint rather than the intended Azure routing.


Automated review by moonbox3's agents

@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Mar 26, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/azure-ai/agent_framework_azure_ai
   _deprecated_azure_openai.py3396281%159–166, 168–169, 171–172, 174, 177–190, 192, 194–200, 202, 204–205, 207, 316, 337, 342, 345, 351, 357, 361, 406, 412–415, 555, 560, 569, 627–628, 637, 870, 878, 884, 888, 911
packages/openai/agent_framework_openai
   _chat_client.py85212984%414, 416–417, 509–512, 516–517, 522–523, 533–534, 541, 556–562, 583, 591, 614, 711, 810, 869, 871, 873, 875, 941, 955, 1035, 1045, 1050, 1093, 1172, 1189, 1202, 1267, 1360, 1365, 1369–1371, 1375–1376, 1442, 1471, 1477, 1487, 1493, 1498, 1504, 1509–1510, 1571, 1593–1594, 1609–1610, 1628–1629, 1670–1673, 1835, 1890, 1892, 1972–1980, 2102, 2137, 2152, 2172–2182, 2195, 2206–2210, 2224, 2238–2249, 2258, 2290–2293, 2301–2302, 2304–2306, 2320–2322, 2332–2333, 2339, 2354
   _chat_completion_client.py3593291%329, 331–332, 417, 498–499, 503, 640, 647, 723–730, 732–735, 745, 823, 825, 842, 863, 891, 904, 928, 948, 988, 1259
   _embedding_client.py81692%210, 212–213, 242, 254, 289
   _shared.py2473785%70, 76–79, 272–274, 288, 306, 310, 316, 335–336, 355, 374–375, 378–379, 381, 407, 409–410, 426, 428, 430, 437, 439, 452, 533, 538, 557, 616–619, 621
TOTAL28001341287% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
5486 20 💤 0 ❌ 0 🔥 1m 26s ⏱️

@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Mar 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 26, 2026
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Mar 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 26, 2026
@chetantoshniwal chetantoshniwal added this pull request to the merge queue Mar 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 26, 2026
@eavanvalkenburg eavanvalkenburg force-pushed the openai_fix_client_setup branch from e424305 to 846b996 Compare March 26, 2026 19:56
eavanvalkenburg and others added 22 commits March 26, 2026 21:36
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>
@eavanvalkenburg eavanvalkenburg force-pushed the openai_fix_client_setup branch from 846b996 to 64642e9 Compare March 26, 2026 20:36
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue Mar 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 26, 2026
@chetantoshniwal chetantoshniwal added this pull request to the merge queue Mar 26, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants