Skip to content

Commit cc0cfaa

Browse files
[BREAKING] Python: fix OpenAI Azure routing and provider samples (#4925)
* Python: fix OpenAI Azure routing and provider samples 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> * fix bandit * Python: align OpenAI embedding Azure routing 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> * Python: fix embedding client pyright check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: thin OpenAI embedding wrapper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: document embedding overload routing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix callable OpenAI key routing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix Azure credential routing tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: address OpenAI review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: narrow Azure routing markers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: refine OpenAI model fallback order Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: narrow Azure deployment docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: remove embedding routing wording Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: run embedding Azure integration tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * changed variable name * Python: expand OpenAI package README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * clarified readme * Python: fix Azure OpenAI integration setup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: correct Azure integration env mapping Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated code to fix int tests * test updates * test fix * fix test setup * updates to tests and setup * remove openai assistants int tests * improvements in int tests * fix env var * fix env vars * fix azure responses test * trigger actions --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3611be8 commit cc0cfaa

103 files changed

Lines changed: 5431 additions & 4196 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/python-integration-tests.yml

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ jobs:
6060
environment: integration
6161
timeout-minutes: 60
6262
env:
63-
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
64-
OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }}
65-
OPENAI_EMBEDDINGS_MODEL_ID: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
63+
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
64+
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
6665
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
6766
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
6867
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
@@ -96,10 +95,10 @@ jobs:
9695
environment: integration
9796
timeout-minutes: 60
9897
env:
99-
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
98+
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
10099
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
101100
AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
102-
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }}
101+
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }}
103102
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
104103
defaults:
105104
run:
@@ -126,7 +125,9 @@ jobs:
126125
uv run pytest --import-mode=importlib
127126
packages/openai/tests/openai/test_openai_chat_completion_client_azure.py
128127
packages/openai/tests/openai/test_openai_chat_client_azure.py
128+
packages/openai/tests/openai/test_openai_embedding_client_azure.py
129129
packages/azure-ai/tests/azure_openai
130+
--ignore=packages/azure-ai/tests/azure_openai/test_azure_responses_client_foundry.py
130131
-m integration
131132
-n logical --dist worksteal
132133
--timeout=120 --session-timeout=900 --timeout_method thread
@@ -202,15 +203,15 @@ jobs:
202203
timeout-minutes: 60
203204
env:
204205
UV_PYTHON: "3.11"
205-
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
206-
OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }}
206+
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
207+
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
207208
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
208-
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
209209
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
210+
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
210211
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
211212
AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
212-
FOUNDRY_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
213-
FOUNDRY_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
213+
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
214+
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
214215
FUNCTIONS_WORKER_RUNTIME: "python"
215216
DURABLE_TASK_SCHEDULER_CONNECTION_STRING: "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"
216217
AzureWebJobsStorage: "UseDevelopmentStorage=true"
@@ -248,17 +249,19 @@ jobs:
248249
--timeout=360 --session-timeout=900 --timeout_method thread
249250
--retries 2 --retry-delay 5
250251
251-
# Azure AI integration tests
252-
python-tests-azure-ai:
253-
name: Python Integration Tests - Azure AI
252+
# Foundry integration tests
253+
python-tests-foundry:
254+
name: Python Integration Tests - Foundry
254255
runs-on: ubuntu-latest
255256
environment: integration
256257
timeout-minutes: 60
257258
env:
258259
AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
259260
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
260-
FOUNDRY_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
261-
FOUNDRY_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
261+
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
262+
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
263+
FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }}
264+
FOUNDRY_AGENT_VERSION: ${{ vars.FOUNDRY_AGENT_VERSION }}
262265
LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }}
263266
defaults:
264267
run:
@@ -282,9 +285,14 @@ jobs:
282285
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
283286
- name: Test with pytest
284287
timeout-minutes: 15
285-
run: |
286-
uv run --directory packages/azure-ai poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
287-
uv run --directory packages/foundry poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
288+
run: >
289+
uv run pytest --import-mode=importlib
290+
packages/azure-ai/tests/azure_openai/test_azure_responses_client_foundry.py
291+
packages/foundry/tests
292+
-m integration
293+
-n logical --dist worksteal
294+
--timeout=120 --session-timeout=900 --timeout_method thread
295+
--retries 2 --retry-delay 5
288296
289297
# Azure Cosmos integration tests
290298
python-tests-cosmos:
@@ -341,7 +349,7 @@ jobs:
341349
python-tests-azure-openai,
342350
python-tests-misc-integration,
343351
python-tests-functions,
344-
python-tests-azure-ai,
352+
python-tests-foundry,
345353
python-tests-cosmos
346354
]
347355
steps:

.github/workflows/python-merge-tests.yml

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,8 @@ jobs:
141141
runs-on: ubuntu-latest
142142
environment: integration
143143
env:
144-
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
145-
OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }}
146-
OPENAI_EMBEDDINGS_MODEL_ID: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
144+
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
145+
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
147146
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
148147
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
149148
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
@@ -195,10 +194,10 @@ jobs:
195194
runs-on: ubuntu-latest
196195
environment: integration
197196
env:
198-
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
197+
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
199198
AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
200199
AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
201-
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }}
200+
AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }}
202201
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
203202
defaults:
204203
run:
@@ -223,7 +222,9 @@ jobs:
223222
uv run pytest --import-mode=importlib
224223
packages/openai/tests/openai/test_openai_chat_completion_client_azure.py
225224
packages/openai/tests/openai/test_openai_chat_client_azure.py
225+
packages/openai/tests/openai/test_openai_embedding_client_azure.py
226226
packages/azure-ai/tests/azure_openai
227+
--ignore=packages/azure-ai/tests/azure_openai/test_azure_responses_client_foundry.py
227228
-m integration
228229
-n logical --dist worksteal
229230
--timeout=120 --session-timeout=900 --timeout_method thread
@@ -333,15 +334,15 @@ jobs:
333334
environment: integration
334335
env:
335336
UV_PYTHON: "3.11"
336-
OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }}
337-
OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }}
337+
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }}
338+
OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
338339
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
339-
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
340340
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
341+
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
341342
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
342343
AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
343-
FOUNDRY_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
344-
FOUNDRY_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
344+
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
345+
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
345346
FUNCTIONS_WORKER_RUNTIME: "python"
346347
DURABLE_TASK_SCHEDULER_CONNECTION_STRING: "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"
347348
AzureWebJobsStorage: "UseDevelopmentStorage=true"
@@ -387,8 +388,8 @@ jobs:
387388
fail-on-empty: false
388389
title: Functions integration test results
389390

390-
python-tests-azure-ai:
391-
name: Python Tests - Azure AI
391+
python-tests-foundry:
392+
name: Python Integration Tests - Foundry
392393
needs: paths-filter
393394
if: >
394395
github.event_name != 'pull_request' &&
@@ -401,8 +402,10 @@ jobs:
401402
env:
402403
AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
403404
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
404-
FOUNDRY_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }}
405-
FOUNDRY_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }}
405+
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
406+
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
407+
FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }}
408+
FOUNDRY_AGENT_VERSION: ${{ vars.FOUNDRY_AGENT_VERSION }}
406409
LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }}
407410
defaults:
408411
run:
@@ -424,9 +427,14 @@ jobs:
424427
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
425428
- name: Test with pytest
426429
timeout-minutes: 15
427-
run: |
428-
uv run --directory packages/azure-ai poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
429-
uv run --directory packages/foundry poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
430+
run: >
431+
uv run pytest --import-mode=importlib
432+
packages/azure-ai/tests/azure_openai/test_azure_responses_client_foundry.py
433+
packages/foundry/tests
434+
-m integration
435+
-n logical --dist worksteal
436+
--timeout=120 --session-timeout=900 --timeout_method thread
437+
--retries 2 --retry-delay 5
430438
working-directory: ./python
431439
- name: Test Azure AI samples
432440
timeout-minutes: 10
@@ -513,7 +521,7 @@ jobs:
513521
python-tests-azure-openai,
514522
python-tests-misc-integration,
515523
python-tests-functions,
516-
python-tests-azure-ai,
524+
python-tests-foundry,
517525
python-tests-cosmos,
518526
]
519527
steps:

python/.env.example

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Azure AI
2-
AZURE_AI_PROJECT_ENDPOINT=""
3-
AZURE_AI_MODEL_DEPLOYMENT_NAME=""
2+
FOUNDRY_PROJECT_ENDPOINT=""
3+
FOUNDRY_MODEL=""
44
# Bing connection for web search (optional, used by samples with web search)
55
BING_CONNECTION_ID=""
66
# Azure AI Search (optional, used by AzureAISearchContextProvider samples)
@@ -13,8 +13,8 @@ AZURE_SEARCH_KNOWLEDGE_BASE_NAME=""
1313
# (different from AZURE_AI_PROJECT_ENDPOINT - Knowledge Base needs OpenAI endpoint for model calls)
1414
# OpenAI
1515
OPENAI_API_KEY=""
16-
OPENAI_CHAT_MODEL_ID=""
17-
OPENAI_RESPONSES_MODEL_ID=""
16+
OPENAI_CHAT_MODEL=""
17+
OPENAI_RESPONSES_MODEL=""
1818
# Azure OpenAI
1919
AZURE_OPENAI_ENDPOINT=""
2020
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME=""

python/DEV_SETUP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ Content of `.env` or `openai.env`:
108108

109109
```env
110110
OPENAI_API_KEY=""
111-
OPENAI_CHAT_MODEL_ID="gpt-4o-mini"
111+
OPENAI_MODEL="gpt-4o-mini"
112112
```
113113

114-
You will then configure the ChatClient class with the keyword argument `env_file_path`:
114+
You will then configure the ChatClient class with the keyword argument `env_file_path` (alternatively you can use `load_dotenv` in your code):
115115

116116
```python
117117
from agent_framework.openai import OpenAIChatClient

python/README.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Set as environment variables, or create a .env file at your project root:
4747

4848
```bash
4949
OPENAI_API_KEY=sk-...
50-
OPENAI_CHAT_MODEL_ID=...
50+
OPENAI_MODEL=...
5151
...
5252
AZURE_OPENAI_API_KEY=...
5353
AZURE_OPENAI_ENDPOINT=...
@@ -57,15 +57,25 @@ FOUNDRY_PROJECT_ENDPOINT=...
5757
FOUNDRY_MODEL=...
5858
```
5959

60+
For the generic OpenAI clients (`OpenAIChatClient` and `OpenAIChatCompletionClient`), configuration
61+
resolves in this order:
62+
63+
1. Explicit Azure inputs such as `credential` or `azure_endpoint`
64+
2. `OPENAI_API_KEY` / explicit OpenAI API-key parameters
65+
3. Azure environment fallback such as `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_API_KEY`
66+
67+
This means mixed shells default to OpenAI when `OPENAI_API_KEY` is present. To force Azure routing,
68+
pass an explicit Azure input such as `credential=AzureCliCredential()`.
69+
6070
You can also override environment variables by explicitly passing configuration parameters to the chat client constructor:
6171

6272
```python
63-
from agent_framework.azure import AzureOpenAIChatClient
73+
from agent_framework.openai import OpenAIChatClient
6474

65-
client = AzureOpenAIChatClient(
75+
client = OpenAIChatClient(
6676
api_key='',
67-
endpoint='',
68-
deployment_name='',
77+
azure_endpoint='',
78+
model='',
6979
api_version='',
7080
)
7181
```

0 commit comments

Comments
 (0)