mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
57fa8ea902
* Fix OpenAIEmbeddingClient with /openai/v1 endpoint (#5068) When base_url ends with /openai/v1/ and a credential is provided, load_openai_service_settings was creating an AsyncAzureOpenAI client. The Azure SDK rewrites deployment-based endpoints (including /embeddings) by inserting /deployments/{model}/ into the URL, producing 404s on the OpenAI-compatible /openai/v1 endpoint. Use AsyncOpenAI instead of AsyncAzureOpenAI when the resolved base_url targets /openai/v1, converting the Azure token provider to an async api_key callable. The responses_mode path is unaffected because the Responses API (/responses) is not in the SDK's rewrite list. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix OpenAIEmbeddingClient to use AsyncOpenAI for /openai/v1 endpoints Fixes #5068 * Address review feedback: improve test coverage and remove unrelated changes - Revert unrelated formatting change in test_a2a_agent.py - Fix test_init_with_openai_v1_base_url_and_api_key_uses_openai_client to exercise the Azure settings path (via AZURE_OPENAI_BASE_URL env var) instead of the plain OpenAI path, covering the elif api_key branch - Add _ensure_async_token_provider unit tests for both sync and async token providers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5068: Python: [Bug]: `OpenAIEmbeddingClient` does not work with `/openai/v1` endpoint --------- Co-authored-by: MAF Dashboard Bot <maf-dashboard-bot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
79 lines
2.5 KiB
Python
79 lines
2.5 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from azure.core.credentials import TokenCredential
|
|
from azure.core.credentials_async import AsyncTokenCredential
|
|
|
|
from agent_framework_openai._shared import (
|
|
AZURE_OPENAI_TOKEN_SCOPE,
|
|
_ensure_async_token_provider,
|
|
_resolve_azure_credential_to_token_provider,
|
|
)
|
|
|
|
|
|
class _AsyncTokenCredentialStub(AsyncTokenCredential):
|
|
async def get_token(self, *scopes: str, **kwargs: object):
|
|
raise NotImplementedError
|
|
|
|
|
|
class _TokenCredentialStub(TokenCredential):
|
|
def get_token(self, *scopes: str, **kwargs: object):
|
|
raise NotImplementedError
|
|
|
|
|
|
def test_resolve_azure_async_credential_wraps_provider() -> None:
|
|
credential = _AsyncTokenCredentialStub()
|
|
token_provider = MagicMock()
|
|
|
|
with patch("azure.identity.aio.get_bearer_token_provider", return_value=token_provider) as mock_provider:
|
|
resolved = _resolve_azure_credential_to_token_provider(credential)
|
|
|
|
assert resolved is token_provider
|
|
mock_provider.assert_called_once_with(credential, AZURE_OPENAI_TOKEN_SCOPE)
|
|
|
|
|
|
def test_resolve_azure_sync_credential_wraps_provider() -> None:
|
|
credential = _TokenCredentialStub()
|
|
token_provider = MagicMock()
|
|
|
|
with patch("azure.identity.get_bearer_token_provider", return_value=token_provider) as mock_provider:
|
|
resolved = _resolve_azure_credential_to_token_provider(credential)
|
|
|
|
assert resolved is token_provider
|
|
mock_provider.assert_called_once_with(credential, AZURE_OPENAI_TOKEN_SCOPE)
|
|
|
|
|
|
def test_resolve_azure_callable_token_provider_passthrough() -> None:
|
|
token_provider = MagicMock()
|
|
|
|
assert _resolve_azure_credential_to_token_provider(token_provider) is token_provider
|
|
|
|
|
|
def test_resolve_azure_invalid_credential_raises() -> None:
|
|
with pytest.raises(ValueError, match="credential"):
|
|
_resolve_azure_credential_to_token_provider(object()) # type: ignore[arg-type]
|
|
|
|
|
|
async def test_ensure_async_token_provider_wraps_sync_provider() -> None:
|
|
def sync_provider() -> str:
|
|
return "sync-token"
|
|
|
|
wrapper = _ensure_async_token_provider(sync_provider)
|
|
result = await wrapper()
|
|
|
|
assert result == "sync-token"
|
|
|
|
|
|
async def test_ensure_async_token_provider_wraps_async_provider() -> None:
|
|
async def async_provider() -> str:
|
|
return "async-token"
|
|
|
|
wrapper = _ensure_async_token_provider(async_provider)
|
|
result = await wrapper()
|
|
|
|
assert result == "async-token"
|