regression URL parsing in PR #231#239
Conversation
Updated parse_azure_endpoint in utils.py:200 to strip the /openai/deployments/... path from the endpoint URL. Previously it only removed the query string, leaving the full deployment path — which AsyncAzureOpenAI then duplicated, causing the 404. Updated test_online.py to use create_chat_model() → model._model.request() — the same _make_azure_provider → AzureProvider(openai_client=AsyncAzureOpenAI(...)) code path used by the rest of the codebase.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Fixes the Azure OpenAI endpoint parsing regression reported in #238 (introduced in PR #231) and applies formatting/cleanup across tooling, library code, and tests.
Changes:
- Update Azure endpoint parsing to strip query strings and deployment paths (tests updated accordingly).
- Add an
Ocp-Apim-Subscription-Keydefault header to Azure OpenAI client construction paths. - Apply formatting/import cleanup across tools, library modules, and tests.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/release.py | Reformat print(..., file=sys.stderr) calls for consistency. |
| tools/query.py | Reformat/refactor typeagent.knowpro imports. |
| src/typeagent/aitools/utils.py | Strip deployment path from Azure endpoint; add APIM subscription header; adjust agent Azure wiring. |
| src/typeagent/aitools/model_adapters.py | Add APIM subscription header to Azure provider client. |
| src/typeagent/knowpro/conversation_base.py | Reformat/refactor imports (including knowledge_schema as kplib). |
| src/typeagent/knowpro/knowledge.py | Reformat imports. |
| src/typeagent/storage/memory/semrefindex.py | Reformat imports. |
| tests/test_utils.py | Update expectations/docs for endpoint parsing (base host only). |
| tests/test_online.py | Switch online test to the create_chat_model (pydantic-ai) execution path. |
| tests/test_semrefindex.py | Reformat imports. |
| tests/test_knowledge.py | Reformat imports. |
| tests/benchmarks/test_benchmark_vectorbase.py | Reformat imports and a long function signature. |
Comments suppressed due to low confidence (1)
src/typeagent/aitools/utils.py:1
- Setting
Ocp-Apim-Subscription-Keyunconditionally to the Azure OpenAI API key is risky and potentially incorrect: this header is typically for Azure API Management (APIM) subscription keys, not for direct Azure OpenAI. It also duplicates sending the secret in an additional header. Consider making this header opt-in (e.g., only set when a dedicated env var likeAZURE_APIM_SUBSCRIPTION_KEYis present) and keep Azure OpenAI auth confined to the standardapi_keymechanism.
# Copyright (c) Microsoft Corporation.
KRRT7
left a comment
There was a problem hiding this comment.
Two edge cases to address before merging:
-
Bare
/openaisuffix not stripped — If an endpoint looks likehttps://foo.openai.azure.com/openai?api-version=..., the current fix leaves/openaiintact.AsyncAzureOpenAI.__init__unconditionally appends/openaito the base URL (seeopenai/lib/azure.py:226-228), producinghttps://foo.openai.azure.com/openai/openai/...→ 404. Trivial fix — add are.sub(r"/openai$", "", clean_endpoint)after the deployment path stripping. -
AZURE_APIM_SUBSCRIPTION_KEYheader missing from the identity branch — The APIM header is only added in theelse(raw key) branch of_make_azure_provider. If someone uses managed identity behind Azure API Management, theOcp-Apim-Subscription-Keyheader is silently omitted. Lift theapim_keylookup anddefault_headersconstruction above theif/elseso both branches get it.
| clean_endpoint = azure_endpoint.split("?", 1)[0] | ||
| deployment_idx = clean_endpoint.find("/openai/deployments/") | ||
| if deployment_idx >= 0: | ||
| clean_endpoint = clean_endpoint[:deployment_idx] |
There was a problem hiding this comment.
This handles /openai/deployments/{name} but misses a bare /openai suffix. AsyncAzureOpenAI always appends /openai to the base URL (see openai/lib/azure.py:226-228), so an endpoint like https://foo.openai.azure.com/openai?api-version=... would produce /openai/openai/....
Suggested addition after this line:
# Also strip a bare /openai suffix — the SDK always appends /openai.
clean_endpoint = re.sub(r"/openai$", "", clean_endpoint)There was a problem hiding this comment.
i think we should use:
# Strip query string and /openai... path — AsyncAzureOpenAI expects a
# clean base URL and builds the deployment path internally.
clean_endpoint = azure_endpoint.split("?", 1)[0]
clean_endpoint = re.sub(r"/openai(/deployments/.*)?$", "", clean_endpoint)
fixes bugs described in #238