mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: [BREAKING] Python: move Azure AI embeddings to Foundry (#5056)
* renamed AzureAIINferenceEmbeddings and lazy load azure-cosmos and env var rename * updated coverage * fix readme
This commit is contained in:
committed by
GitHub
Unverified
parent
47d82911c0
commit
95fd5ec658
+12
-3
@@ -1,6 +1,15 @@
|
||||
# Azure AI
|
||||
# Microsoft Foundry
|
||||
FOUNDRY_PROJECT_ENDPOINT=""
|
||||
# Model used for FoundryChatClient
|
||||
FOUNDRY_MODEL=""
|
||||
# Foundry Agents (prompt or hosted agents)
|
||||
FOUNDRY_AGENT_NAME=""
|
||||
FOUNDRY_AGENT_VERSION=""
|
||||
# Microsoft Foundry Models endpoint, used by embeddings
|
||||
FOUNDRY_MODELS_ENDPOINT=""
|
||||
FOUNDRY_MODELS_API_KEY=""
|
||||
FOUNDRY_EMBEDDING_MODEL=""
|
||||
FOUNDRY_IMAGE_EMBEDDING_MODEL=""
|
||||
# Bing connection for web search (optional, used by samples with web search)
|
||||
BING_CONNECTION_ID=""
|
||||
# Azure AI Search (optional, used by AzureAISearchContextProvider samples)
|
||||
@@ -13,12 +22,12 @@ AZURE_SEARCH_KNOWLEDGE_BASE_NAME=""
|
||||
# (different from AZURE_AI_PROJECT_ENDPOINT - Knowledge Base needs OpenAI endpoint for model calls)
|
||||
# OpenAI
|
||||
OPENAI_API_KEY=""
|
||||
OPENAI_CHAT_COMPLETION_MODEL=""
|
||||
OPENAI_CHAT_MODEL=""
|
||||
OPENAI_RESPONSES_MODEL=""
|
||||
# Azure OpenAI
|
||||
AZURE_OPENAI_ENDPOINT=""
|
||||
AZURE_OPENAI_CHAT_COMPLETION_MODEL=""
|
||||
AZURE_OPENAI_CHAT_MODEL=""
|
||||
AZURE_OPENAI_RESPONSES_MODEL=""
|
||||
# Mem0
|
||||
MEM0_API_KEY=""
|
||||
# Copilot Studio
|
||||
|
||||
@@ -15,7 +15,7 @@ python/
|
||||
├── pyproject.toml # Root package (agent-framework)
|
||||
├── packages/
|
||||
│ ├── core/ # agent-framework-core (main package)
|
||||
│ ├── azure-ai/ # agent-framework-azure-ai
|
||||
│ ├── foundry/ # agent-framework-foundry
|
||||
│ ├── anthropic/ # agent-framework-anthropic
|
||||
│ └── ... # Other connector packages
|
||||
```
|
||||
@@ -76,9 +76,9 @@ uv run poe add-dependency-and-validate-bounds --package core --dependency "<depe
|
||||
Provider folders in core use `__getattr__` to lazy load from connector packages:
|
||||
|
||||
```python
|
||||
# In agent_framework/azure/__init__.py
|
||||
# In agent_framework/foundry/__init__.py
|
||||
_IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"AzureAIAgentClient": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"FoundryChatClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
}
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ The merge CI workflow (`python-merge-tests.yml`) splits integration tests into p
|
||||
- **Azure OpenAI integration** — runs when `packages/core/agent_framework/azure/` or core changes
|
||||
- **Misc integration** — Anthropic, Ollama, MCP tests; runs when their packages or core change
|
||||
- **Functions integration** — Azure Functions + Durable Task; runs when their packages or core change
|
||||
- **Azure AI integration** — runs when `packages/azure-ai/` or core changes
|
||||
- **Foundry integration** — runs when `packages/foundry/` or core changes
|
||||
|
||||
Core infrastructure changes (e.g., `_agents.py`, `_types.py`) trigger all integration test jobs. Scheduled and manual runs always execute all jobs.
|
||||
|
||||
|
||||
+4
-3
@@ -40,7 +40,7 @@ python/
|
||||
│ ├── core/ # agent-framework-core (main package)
|
||||
│ │ ├── agent_framework/ # Public API exports
|
||||
│ │ └── tests/
|
||||
│ ├── azure-ai/ # agent-framework-azure-ai
|
||||
│ ├── foundry/ # agent-framework-foundry
|
||||
│ ├── anthropic/ # agent-framework-anthropic
|
||||
│ ├── ollama/ # agent-framework-ollama
|
||||
│ └── ... # Other provider packages
|
||||
@@ -52,7 +52,7 @@ python/
|
||||
### Package Relationships
|
||||
|
||||
- `agent-framework-core` contains core abstractions and OpenAI/Azure OpenAI built-in
|
||||
- Provider packages (`azure-ai`, `anthropic`, etc.) extend core with specific integrations
|
||||
- Provider packages (`foundry`, `anthropic`, etc.) extend core with specific integrations
|
||||
- Core uses lazy loading via `__getattr__` in provider folders (e.g., `agent_framework/azure/`)
|
||||
|
||||
## Package Documentation
|
||||
@@ -68,8 +68,9 @@ python/
|
||||
- [ollama](packages/ollama/AGENTS.md) - Local Ollama inference
|
||||
|
||||
### Azure Integrations
|
||||
- [azure-ai](packages/azure-ai/AGENTS.md) - Azure AI Foundry agents
|
||||
- [foundry](packages/foundry/README.md) - Microsoft Foundry chat, agent, memory, and embedding integrations
|
||||
- [azure-ai-search](packages/azure-ai-search/AGENTS.md) - Azure AI Search RAG
|
||||
- [azure-cosmos](packages/azure-cosmos/AGENTS.md) - Azure Cosmos DB-backed history provider
|
||||
- [azurefunctions](packages/azurefunctions/AGENTS.md) - Azure Functions hosting
|
||||
|
||||
### Protocols & UI
|
||||
|
||||
@@ -325,14 +325,15 @@ python/
|
||||
│ │ ├── mem0/ # Lazy loads from agent-framework-mem0
|
||||
│ │ └── redis/ # Lazy loads from agent-framework-redis
|
||||
│ │
|
||||
│ ├── azure-ai/ # agent-framework-azure-ai
|
||||
│ ├── foundry/ # agent-framework-foundry
|
||||
│ │ ├── pyproject.toml
|
||||
│ │ ├── tests/
|
||||
│ │ └── agent_framework_azure_ai/
|
||||
│ │ └── agent_framework_foundry/
|
||||
│ │ ├── __init__.py # Public exports
|
||||
│ │ ├── _chat_client.py # AzureAIClient implementation
|
||||
│ │ ├── _client.py # AzureAIAgentClient implementation
|
||||
│ │ ├── _shared.py # AzureAISettings and shared utilities
|
||||
│ │ ├── _chat_client.py # FoundryChatClient implementation
|
||||
│ │ ├── _agent.py # FoundryAgent implementation
|
||||
│ │ ├── _embedding_client.py # FoundryEmbeddingClient implementation
|
||||
│ │ ├── _memory_provider.py # Foundry memory implementation
|
||||
│ │ └── py.typed # PEP 561 marker
|
||||
│ ├── anthropic/ # agent-framework-anthropic
|
||||
│ ├── bedrock/ # agent-framework-bedrock
|
||||
@@ -345,9 +346,9 @@ python/
|
||||
Provider folders in the core package use `__getattr__` to lazy load classes from their respective connector packages. This allows users to import from a consistent location while only loading dependencies when needed:
|
||||
|
||||
```python
|
||||
# In agent_framework/azure/__init__.py
|
||||
# In agent_framework/foundry/__init__.py
|
||||
_IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"AzureAIAgentClient": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"FoundryChatClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
# ...
|
||||
}
|
||||
|
||||
@@ -419,7 +420,7 @@ pip install agent-framework-core[all]
|
||||
pip install agent-framework
|
||||
|
||||
# Install specific connector (pulls in core as dependency)
|
||||
pip install agent-framework-azure-ai
|
||||
pip install agent-framework-foundry
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
+1
-1
@@ -249,7 +249,7 @@ For more advanced orchestration patterns including Sequential, Concurrent, Group
|
||||
|
||||
- [Getting Started with Agents](samples/02-agents): Basic agent creation and tool usage
|
||||
- [Chat Client Examples](samples/02-agents/chat_client): Direct chat client usage patterns
|
||||
- [Azure AI Integration](https://github.com/microsoft/agent-framework/tree/main/python/packages/azure-ai): Azure AI integration
|
||||
- [Foundry Integration](https://github.com/microsoft/agent-framework/tree/main/python/packages/foundry): Microsoft Foundry integration
|
||||
- [Workflow Samples](samples/03-workflows): Advanced multi-agent patterns
|
||||
|
||||
## Agent Framework Documentation
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# Azure AI Package (agent-framework-azure-ai)
|
||||
|
||||
Integration with Azure AI inference embeddings plus shared Azure authentication helpers.
|
||||
|
||||
## Main Classes
|
||||
|
||||
- **`AzureAIInferenceEmbeddingClient`** - Full-featured Azure AI inference embeddings client
|
||||
- **`RawAzureAIInferenceEmbeddingClient`** - Raw embeddings client without middleware layers
|
||||
- **`AzureAIInferenceEmbeddingOptions`** / **`AzureAIInferenceEmbeddingSettings`** - Embedding options and settings
|
||||
- **`AzureAISettings`** - Shared Azure AI project settings TypedDict
|
||||
- **`AzureCredentialTypes`** / **`AzureTokenProvider`** - Shared Azure authentication helpers
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from agent_framework_azure_ai import AzureAIInferenceEmbeddingClient
|
||||
|
||||
client = AzureAIInferenceEmbeddingClient(
|
||||
endpoint="https://<resource>.inference.ai.azure.com",
|
||||
api_key="...",
|
||||
model="text-embedding-3-large",
|
||||
)
|
||||
result = await client.get_embeddings(["Hello"])
|
||||
```
|
||||
|
||||
## Import Path
|
||||
|
||||
```python
|
||||
from agent_framework_azure_ai import AzureAIInferenceEmbeddingClient
|
||||
```
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
@@ -1,26 +0,0 @@
|
||||
# Get Started with Microsoft Agent Framework Azure AI
|
||||
|
||||
Please install this package via pip:
|
||||
|
||||
```bash
|
||||
pip install agent-framework-azure-ai --pre
|
||||
```
|
||||
|
||||
## Foundry Memory Context Provider
|
||||
|
||||
The Foundry Memory context provider enables semantic memory capabilities for your agents using Azure AI Foundry Memory Store. It automatically:
|
||||
- Retrieves static (user profile) memories on first run
|
||||
- Searches for contextual memories based on conversation
|
||||
- Updates the memory store with new conversation messages
|
||||
|
||||
### Basic Usage Example
|
||||
|
||||
See the [Foundry Memory example](../../samples/02-agents/context_providers/azure_ai_foundry_memory.py) which demonstrates:
|
||||
|
||||
- Creating a memory store using Azure AI Projects client
|
||||
- Setting up an agent with FoundryMemoryProvider
|
||||
- Teaching the agent user preferences
|
||||
- Retrieving information using remembered context across conversations
|
||||
- Automatic memory updates with configurable delays
|
||||
|
||||
and see the [README](https://github.com/microsoft/agent-framework/tree/main/python/README.md) for more information.
|
||||
@@ -1,28 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import importlib.metadata
|
||||
|
||||
from ._embedding_client import (
|
||||
AzureAIInferenceEmbeddingClient,
|
||||
AzureAIInferenceEmbeddingOptions,
|
||||
AzureAIInferenceEmbeddingSettings,
|
||||
RawAzureAIInferenceEmbeddingClient,
|
||||
)
|
||||
from ._entra_id_authentication import AzureCredentialTypes, AzureTokenProvider
|
||||
from ._shared import AzureAISettings
|
||||
|
||||
try:
|
||||
__version__ = importlib.metadata.version(__name__)
|
||||
except importlib.metadata.PackageNotFoundError:
|
||||
__version__ = "0.0.0"
|
||||
|
||||
__all__ = [
|
||||
"AzureAIInferenceEmbeddingClient",
|
||||
"AzureAIInferenceEmbeddingOptions",
|
||||
"AzureAIInferenceEmbeddingSettings",
|
||||
"AzureAISettings",
|
||||
"AzureCredentialTypes",
|
||||
"AzureTokenProvider",
|
||||
"RawAzureAIInferenceEmbeddingClient",
|
||||
"__version__",
|
||||
]
|
||||
@@ -1,67 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import Awaitable, Callable
|
||||
from typing import Union
|
||||
|
||||
from agent_framework.exceptions import ChatClientInvalidAuthException
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.core.credentials_async import AsyncTokenCredential
|
||||
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
AzureTokenProvider = Callable[[], Union[str, Awaitable[str]]]
|
||||
"""A callable that returns a bearer token string, either synchronously or asynchronously."""
|
||||
|
||||
AzureCredentialTypes = Union[TokenCredential, AsyncTokenCredential]
|
||||
"""Union of Azure credential types.
|
||||
|
||||
Accepts:
|
||||
- ``TokenCredential`` — synchronous Azure credential (e.g. ``DefaultAzureCredential()``)
|
||||
- ``AsyncTokenCredential`` — asynchronous Azure credential (e.g. ``azure.identity.aio.DefaultAzureCredential()``)
|
||||
"""
|
||||
|
||||
|
||||
def resolve_credential_to_token_provider(
|
||||
credential: AzureCredentialTypes | AzureTokenProvider,
|
||||
token_endpoint: str | None,
|
||||
) -> AzureTokenProvider:
|
||||
"""Convert an Azure credential or token provider into an ``ad_token_provider`` callable.
|
||||
|
||||
If the credential is already a callable token provider, it is returned as-is
|
||||
(``token_endpoint`` is not required in this case).
|
||||
If it is a ``TokenCredential`` or ``AsyncTokenCredential``, it is wrapped using
|
||||
``azure.identity.get_bearer_token_provider`` (sync or async variant) which
|
||||
handles token caching and automatic refresh.
|
||||
|
||||
Args:
|
||||
credential: An Azure credential or token provider callable.
|
||||
token_endpoint: The token scope/endpoint
|
||||
(e.g. ``"https://cognitiveservices.azure.com/.default"``).
|
||||
Required when ``credential`` is a ``TokenCredential`` or ``AsyncTokenCredential``.
|
||||
|
||||
Returns:
|
||||
A callable that returns a bearer token string (sync or async).
|
||||
|
||||
Raises:
|
||||
ServiceInvalidAuthError: If the token endpoint is empty when needed for credential wrapping.
|
||||
"""
|
||||
# Already a token provider callable (not a credential object) — use directly
|
||||
if callable(credential) and not isinstance(credential, (TokenCredential, AsyncTokenCredential)):
|
||||
return credential
|
||||
|
||||
if not token_endpoint:
|
||||
raise ChatClientInvalidAuthException(
|
||||
"A token endpoint must be provided either in settings, as an environment variable, or as an argument."
|
||||
)
|
||||
|
||||
if isinstance(credential, AsyncTokenCredential):
|
||||
from azure.identity.aio import get_bearer_token_provider as get_async_bearer_token_provider
|
||||
|
||||
return get_async_bearer_token_provider(credential, token_endpoint)
|
||||
|
||||
from azure.identity import get_bearer_token_provider
|
||||
|
||||
return get_bearer_token_provider(credential, token_endpoint) # type: ignore[arg-type]
|
||||
@@ -1,48 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
from typing import TypedDict # pragma: no cover
|
||||
else:
|
||||
from typing_extensions import TypedDict # type: ignore # pragma: no cover
|
||||
|
||||
|
||||
class AzureAISettings(TypedDict, total=False):
|
||||
"""Azure AI Project settings.
|
||||
|
||||
Settings are resolved in this order: explicit keyword arguments, values from an
|
||||
explicitly provided .env file, then environment variables with the prefix
|
||||
'AZURE_AI_'. If settings are missing after resolution, validation will fail.
|
||||
|
||||
Keyword Args:
|
||||
project_endpoint: The Azure AI Project endpoint URL.
|
||||
Can be set via environment variable AZURE_AI_PROJECT_ENDPOINT.
|
||||
model: The name of the model to use.
|
||||
Can be set via environment variable AZURE_AI_MODEL.
|
||||
env_file_path: If provided, the .env settings are read from this file path location.
|
||||
env_file_encoding: The encoding of the .env file, defaults to 'utf-8'.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
from agent_framework.azure import AzureAISettings
|
||||
|
||||
# Using environment variables
|
||||
# Set AZURE_AI_PROJECT_ENDPOINT=https://your-project.cognitiveservices.azure.com
|
||||
# Set AZURE_AI_MODEL=gpt-4
|
||||
settings = AzureAISettings()
|
||||
|
||||
# Or passing parameters directly
|
||||
settings = AzureAISettings(
|
||||
project_endpoint="https://your-project.cognitiveservices.azure.com", model="gpt-4"
|
||||
)
|
||||
|
||||
# Or loading from a .env file
|
||||
settings = AzureAISettings(env_file_path="path/to/.env")
|
||||
"""
|
||||
|
||||
project_endpoint: str | None
|
||||
model: str | None
|
||||
@@ -1,109 +0,0 @@
|
||||
[project]
|
||||
name = "agent-framework-azure-ai"
|
||||
description = "Azure AI Foundry integration for Microsoft Agent Framework."
|
||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
version = "1.0.0rc6"
|
||||
license-files = ["LICENSE"]
|
||||
urls.homepage = "https://aka.ms/agent-framework"
|
||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||
urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
|
||||
urls.issues = "https://github.com/microsoft/agent-framework/issues"
|
||||
classifiers = [
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
"Typing :: Typed",
|
||||
]
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-openai>=1.0.0rc6",
|
||||
"azure-ai-projects>=2.0.0,<3.0",
|
||||
"azure-ai-agents>=1.2.0b5,<1.2.0b6",
|
||||
"azure-ai-inference>=1.0.0b9,<1.0.0b10",
|
||||
"azure-identity>=1,<2",
|
||||
"aiohttp>=3.7.0,<4",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
prerelease = "if-necessary-or-explicit"
|
||||
environments = [
|
||||
"sys_platform == 'darwin'",
|
||||
"sys_platform == 'linux'",
|
||||
"sys_platform == 'win32'"
|
||||
]
|
||||
|
||||
[tool.uv-dynamic-versioning]
|
||||
fallback-version = "0.0.0"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = 'tests'
|
||||
addopts = "-ra -q -r fEX"
|
||||
asyncio_mode = "auto"
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
filterwarnings = []
|
||||
timeout = 120
|
||||
markers = [
|
||||
"integration: marks tests as integration tests that require external services",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
extend = "../../pyproject.toml"
|
||||
|
||||
[tool.coverage.run]
|
||||
omit = [
|
||||
"**/__init__.py"
|
||||
]
|
||||
|
||||
[tool.pyright]
|
||||
extends = "../../pyproject.toml"
|
||||
include = ["agent_framework_azure_ai"]
|
||||
|
||||
[tool.mypy]
|
||||
plugins = ['pydantic.mypy']
|
||||
strict = true
|
||||
python_version = "3.10"
|
||||
ignore_missing_imports = true
|
||||
disallow_untyped_defs = true
|
||||
no_implicit_optional = true
|
||||
check_untyped_defs = true
|
||||
warn_return_any = true
|
||||
show_error_codes = true
|
||||
warn_unused_ignores = false
|
||||
disallow_incomplete_defs = true
|
||||
disallow_untyped_decorators = true
|
||||
|
||||
[tool.bandit]
|
||||
targets = ["agent_framework_azure_ai"]
|
||||
exclude_dirs = ["tests"]
|
||||
|
||||
[tool.poe]
|
||||
executor.type = "uv"
|
||||
include = "../../shared_tasks.toml"
|
||||
|
||||
[tool.poe.tasks.mypy]
|
||||
help = "Run MyPy for this package."
|
||||
cmd = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_azure_ai"
|
||||
|
||||
[tool.poe.tasks.test]
|
||||
help = "Run the default unit test suite for this package."
|
||||
cmd = 'pytest -m "not integration" --cov=agent_framework_azure_ai --cov-report=term-missing:skip-covered tests'
|
||||
|
||||
[tool.poe.tasks.integration-tests]
|
||||
help = "Run the package integration test suite."
|
||||
cmd = """
|
||||
pytest --import-mode=importlib
|
||||
-n logical --dist worksteal
|
||||
tests
|
||||
"""
|
||||
|
||||
[build-system]
|
||||
requires = ["flit-core >= 3.11,<4.0"]
|
||||
build-backend = "flit_core.buildapi"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 178 KiB |
@@ -1,61 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from agent_framework.exceptions import ChatClientInvalidAuthException
|
||||
from azure.core.credentials import TokenCredential
|
||||
from azure.core.credentials_async import AsyncTokenCredential
|
||||
|
||||
from agent_framework_azure_ai._entra_id_authentication import (
|
||||
resolve_credential_to_token_provider,
|
||||
)
|
||||
|
||||
TOKEN_ENDPOINT = "https://cognitiveservices.azure.com/.default"
|
||||
|
||||
|
||||
def test_resolve_sync_credential_returns_provider() -> None:
|
||||
"""Test that a sync TokenCredential is resolved via azure.identity.get_bearer_token_provider."""
|
||||
mock_credential = MagicMock(spec=TokenCredential)
|
||||
mock_provider = MagicMock(return_value="token-string")
|
||||
|
||||
with patch("azure.identity.get_bearer_token_provider", return_value=mock_provider) as mock_gbtp:
|
||||
result = resolve_credential_to_token_provider(mock_credential, TOKEN_ENDPOINT)
|
||||
|
||||
mock_gbtp.assert_called_once_with(mock_credential, TOKEN_ENDPOINT)
|
||||
assert result is mock_provider
|
||||
|
||||
|
||||
def test_resolve_async_credential_returns_provider() -> None:
|
||||
"""Test that an AsyncTokenCredential is resolved via azure.identity.aio.get_bearer_token_provider."""
|
||||
mock_credential = MagicMock(spec=AsyncTokenCredential)
|
||||
mock_provider = MagicMock(return_value="token-string")
|
||||
|
||||
with patch("azure.identity.aio.get_bearer_token_provider", return_value=mock_provider) as mock_gbtp:
|
||||
result = resolve_credential_to_token_provider(mock_credential, TOKEN_ENDPOINT)
|
||||
|
||||
mock_gbtp.assert_called_once_with(mock_credential, TOKEN_ENDPOINT)
|
||||
assert result is mock_provider
|
||||
|
||||
|
||||
def test_resolve_callable_provider_passthrough() -> None:
|
||||
"""Test that a callable token provider is returned as-is, without needing token_endpoint."""
|
||||
my_provider = lambda: "my-token" # noqa: E731
|
||||
|
||||
# Works with token_endpoint
|
||||
assert resolve_credential_to_token_provider(my_provider, TOKEN_ENDPOINT) is my_provider
|
||||
|
||||
# Also works without token_endpoint
|
||||
assert resolve_credential_to_token_provider(my_provider, None) is my_provider
|
||||
assert resolve_credential_to_token_provider(my_provider, "") is my_provider
|
||||
|
||||
|
||||
def test_resolve_missing_endpoint_raises() -> None:
|
||||
"""Test that missing token endpoint raises ChatClientInvalidAuthException."""
|
||||
mock_credential = MagicMock(spec=TokenCredential)
|
||||
|
||||
with pytest.raises(ChatClientInvalidAuthException, match="A token endpoint must be provided"):
|
||||
resolve_credential_to_token_provider(mock_credential, "")
|
||||
|
||||
with pytest.raises(ChatClientInvalidAuthException, match="A token endpoint must be provided"):
|
||||
resolve_credential_to_token_provider(mock_credential, None) # type: ignore[arg-type]
|
||||
@@ -1,78 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from pytest import fixture
|
||||
|
||||
|
||||
@fixture
|
||||
def exclude_list(request: Any) -> list[str]:
|
||||
"""Fixture that returns a list of environment variables to exclude."""
|
||||
return request.param if hasattr(request, "param") else []
|
||||
|
||||
|
||||
@fixture
|
||||
def override_env_param_dict(request: Any) -> dict[str, str]:
|
||||
"""Fixture that returns a dict of environment variables to override."""
|
||||
return request.param if hasattr(request, "param") else {}
|
||||
|
||||
|
||||
@fixture()
|
||||
def azure_ai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
|
||||
"""Fixture to set environment variables for AzureAISettings."""
|
||||
|
||||
if exclude_list is None:
|
||||
exclude_list = []
|
||||
|
||||
if override_env_param_dict is None:
|
||||
override_env_param_dict = {}
|
||||
|
||||
env_vars = {
|
||||
"AZURE_AI_PROJECT_ENDPOINT": "https://test-project.cognitiveservices.azure.com/",
|
||||
"AZURE_AI_MODEL": "test-gpt-4o",
|
||||
}
|
||||
|
||||
env_vars.update(override_env_param_dict) # type: ignore
|
||||
|
||||
for key, value in env_vars.items():
|
||||
if key in exclude_list:
|
||||
monkeypatch.delenv(key, raising=False) # type: ignore
|
||||
continue
|
||||
monkeypatch.setenv(key, value) # type: ignore
|
||||
|
||||
return env_vars
|
||||
|
||||
|
||||
@fixture
|
||||
def mock_agents_client() -> MagicMock:
|
||||
"""Fixture that provides a mock AgentsClient."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
# Mock agents property
|
||||
mock_client.create_agent = AsyncMock()
|
||||
mock_client.delete_agent = AsyncMock()
|
||||
|
||||
# Mock agent creation response
|
||||
mock_agent = MagicMock()
|
||||
mock_agent.id = "test-agent-id"
|
||||
mock_client.create_agent.return_value = mock_agent
|
||||
|
||||
# Mock threads property
|
||||
mock_client.threads = MagicMock()
|
||||
mock_client.threads.create = AsyncMock()
|
||||
mock_client.messages.create = AsyncMock()
|
||||
|
||||
# Mock runs property
|
||||
mock_client.runs = MagicMock()
|
||||
mock_client.runs.list = AsyncMock()
|
||||
mock_client.runs.cancel = AsyncMock()
|
||||
mock_client.runs.stream = AsyncMock()
|
||||
mock_client.runs.submit_tool_outputs_stream = AsyncMock()
|
||||
|
||||
return mock_client
|
||||
|
||||
|
||||
@fixture
|
||||
def mock_azure_credential() -> MagicMock:
|
||||
"""Fixture that provides a mock AsyncTokenCredential."""
|
||||
return MagicMock()
|
||||
@@ -1,76 +0,0 @@
|
||||
%PDF-1.7
|
||||
%����
|
||||
1 0 obj
|
||||
<</Type/Catalog/Pages 2 0 R/Lang(en) /StructTreeRoot 22 0 R/MarkInfo<</Marked true>>/Metadata 132 0 R/ViewerPreferences 133 0 R>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<</Type/Pages/Count 1/Kids[ 4 0 R] >>
|
||||
endobj
|
||||
3 0 obj
|
||||
<</Author(Test Author) /Creator(Test Creator) /Title(Employee Directory) >>
|
||||
endobj
|
||||
4 0 obj
|
||||
<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]/Resources<</Font<</F1 5 0 R>>>>/Contents 6 0 R>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<</Type/Font/Subtype/Type1/BaseFont/Times-Roman>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<</Length 200>>
|
||||
stream
|
||||
BT
|
||||
/F1 12 Tf
|
||||
50 750 Td
|
||||
(Employee Directory) Tj
|
||||
0 -30 Td
|
||||
(Name: John Smith) Tj
|
||||
0 -15 Td
|
||||
(Department: Engineering) Tj
|
||||
0 -15 Td
|
||||
(Age: 28) Tj
|
||||
0 -30 Td
|
||||
(Name: Alice Johnson) Tj
|
||||
0 -15 Td
|
||||
(Department: Sales) Tj
|
||||
0 -15 Td
|
||||
(Age: 24) Tj
|
||||
0 -30 Td
|
||||
(Name: Bob Wilson) Tj
|
||||
0 -15 Td
|
||||
(Department: Marketing) Tj
|
||||
0 -15 Td
|
||||
(Age: 35) Tj
|
||||
ET
|
||||
endstream
|
||||
endobj
|
||||
22 0 obj
|
||||
<</Type/StructTreeRoot>>
|
||||
endobj
|
||||
132 0 obj
|
||||
<</Type/Metadata/Subtype/XML>>
|
||||
endobj
|
||||
133 0 obj
|
||||
<</DisplayDocTitle true>>
|
||||
endobj
|
||||
xref
|
||||
0 10
|
||||
0000000000 65535 f
|
||||
0000000015 00000 n
|
||||
0000000152 00000 n
|
||||
0000000209 00000 n
|
||||
0000000300 00000 n
|
||||
0000000420 00000 n
|
||||
0000000490 00000 n
|
||||
0000000000 65535 f
|
||||
0000000000 65535 f
|
||||
0000000000 65535 f
|
||||
22 1
|
||||
0000000740 00000 n
|
||||
132 2
|
||||
0000000780 00000 n
|
||||
0000000820 00000 n
|
||||
trailer
|
||||
<</Size 134/Root 1 0 R/Info 3 0 R>>
|
||||
startxref
|
||||
860
|
||||
%%EOF
|
||||
@@ -9,7 +9,7 @@ Azure Cosmos DB history provider integration for Agent Framework.
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
from agent_framework.azure import CosmosHistoryProvider
|
||||
|
||||
provider = CosmosHistoryProvider(
|
||||
endpoint="https://<account>.documents.azure.com:443/",
|
||||
@@ -24,5 +24,7 @@ Container name is configured on the provider. `session_id` is used as the partit
|
||||
## Import Path
|
||||
|
||||
```python
|
||||
from agent_framework.azure import CosmosHistoryProvider
|
||||
# or directly:
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ The Azure Cosmos DB integration provides `CosmosHistoryProvider` for persistent
|
||||
|
||||
```python
|
||||
from azure.identity.aio import DefaultAzureCredential
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
from agent_framework.azure import CosmosHistoryProvider
|
||||
|
||||
provider = CosmosHistoryProvider(
|
||||
endpoint="https://<account>.documents.azure.com:443/",
|
||||
@@ -35,4 +35,13 @@ Container naming behavior:
|
||||
- Container name is configured on the provider (`container_name` or `AZURE_COSMOS_CONTAINER_NAME`)
|
||||
- `session_id` is used as the Cosmos partition key for reads/writes
|
||||
|
||||
See `samples/cosmos_history_provider.py` for a runnable package-local example.
|
||||
See the [conversation samples](../../samples/02-agents/conversations/) for runnable examples, including
|
||||
[`cosmos_history_provider.py`](../../samples/02-agents/conversations/cosmos_history_provider.py).
|
||||
|
||||
## Import Paths
|
||||
|
||||
```python
|
||||
from agent_framework.azure import CosmosHistoryProvider
|
||||
# or directly:
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
```
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Azure Cosmos DB Package Samples
|
||||
|
||||
This folder contains samples for `agent-framework-azure-cosmos`.
|
||||
|
||||
| File | Description |
|
||||
| --- | --- |
|
||||
| [`cosmos_history_provider.py`](cosmos_history_provider.py) | Demonstrates an Agent using `CosmosHistoryProvider` with `FoundryChatClient` (configured against an Azure AI Foundry project endpoint), provider-configured container name, and `session_id` partitioning. |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `AZURE_COSMOS_ENDPOINT`
|
||||
- `AZURE_COSMOS_DATABASE_NAME`
|
||||
- `AZURE_COSMOS_CONTAINER_NAME`
|
||||
- `AZURE_COSMOS_KEY` (or equivalent credential flow)
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
uv run --directory packages/azure-cosmos python samples/cosmos_history_provider.py
|
||||
```
|
||||
@@ -1,3 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Samples for the Azure Cosmos history provider package."""
|
||||
@@ -34,8 +34,8 @@ FOUNDRY_PROJECT_ENDPOINT=...
|
||||
FOUNDRY_MODEL=...
|
||||
...
|
||||
OPENAI_API_KEY=sk-...
|
||||
OPENAI_CHAT_COMPLETION_MODEL=...
|
||||
OPENAI_CHAT_MODEL=...
|
||||
OPENAI_RESPONSES_MODEL=...
|
||||
...
|
||||
AZURE_OPENAI_API_KEY=...
|
||||
AZURE_OPENAI_ENDPOINT=...
|
||||
|
||||
@@ -14,13 +14,7 @@ _IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"AgentResponseCallbackProtocol": ("agent_framework_durabletask", "agent-framework-durabletask"),
|
||||
"AzureAISearchContextProvider": ("agent_framework_azure_ai_search", "agent-framework-azure-ai-search"),
|
||||
"AzureAISearchSettings": ("agent_framework_azure_ai_search", "agent-framework-azure-ai-search"),
|
||||
"AzureAISettings": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"AzureAIInferenceEmbeddingClient": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"AzureAIInferenceEmbeddingOptions": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"AzureAIInferenceEmbeddingSettings": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"RawAzureAIInferenceEmbeddingClient": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"AzureCredentialTypes": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"AzureTokenProvider": ("agent_framework_azure_ai", "agent-framework-azure-ai"),
|
||||
"CosmosHistoryProvider": ("agent_framework_azure_cosmos", "agent-framework-azure-cosmos"),
|
||||
"DurableAIAgent": ("agent_framework_durabletask", "agent-framework-durabletask"),
|
||||
"DurableAIAgentClient": ("agent_framework_durabletask", "agent-framework-durabletask"),
|
||||
"DurableAIAgentOrchestrationContext": ("agent_framework_durabletask", "agent-framework-durabletask"),
|
||||
|
||||
@@ -3,19 +3,11 @@
|
||||
# Type stubs for the agent_framework.azure lazy-loading namespace.
|
||||
# Install the relevant packages for full type support.
|
||||
|
||||
from agent_framework_azure_ai import (
|
||||
AzureAIInferenceEmbeddingClient,
|
||||
AzureAIInferenceEmbeddingOptions,
|
||||
AzureAIInferenceEmbeddingSettings,
|
||||
AzureAISettings,
|
||||
AzureCredentialTypes,
|
||||
AzureTokenProvider,
|
||||
RawAzureAIInferenceEmbeddingClient,
|
||||
)
|
||||
from agent_framework_azure_ai_search import (
|
||||
AzureAISearchContextProvider,
|
||||
AzureAISearchSettings,
|
||||
)
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
from agent_framework_azurefunctions import AgentFunctionApp
|
||||
from agent_framework_durabletask import (
|
||||
AgentCallbackContext,
|
||||
@@ -30,17 +22,11 @@ __all__ = [
|
||||
"AgentCallbackContext",
|
||||
"AgentFunctionApp",
|
||||
"AgentResponseCallbackProtocol",
|
||||
"AzureAIInferenceEmbeddingClient",
|
||||
"AzureAIInferenceEmbeddingOptions",
|
||||
"AzureAIInferenceEmbeddingSettings",
|
||||
"AzureAISearchContextProvider",
|
||||
"AzureAISearchSettings",
|
||||
"AzureAISettings",
|
||||
"AzureCredentialTypes",
|
||||
"AzureTokenProvider",
|
||||
"CosmosHistoryProvider",
|
||||
"DurableAIAgent",
|
||||
"DurableAIAgentClient",
|
||||
"DurableAIAgentOrchestrationContext",
|
||||
"DurableAIAgentWorker",
|
||||
"RawAzureAIInferenceEmbeddingClient",
|
||||
]
|
||||
|
||||
@@ -16,6 +16,9 @@ _IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"FoundryAgent": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryChatClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryChatOptions": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryEmbeddingClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryEmbeddingOptions": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryEmbeddingSettings": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryEvals": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryMemoryProvider": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"FoundryLocalChatOptions": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
@@ -25,6 +28,7 @@ _IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"RawFoundryAgent": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"RawFoundryAgentChatClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"RawFoundryChatClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"RawFoundryEmbeddingClient": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"evaluate_foundry_target": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
"evaluate_traces": ("agent_framework_foundry", "agent-framework-foundry"),
|
||||
}
|
||||
|
||||
@@ -8,11 +8,15 @@ from agent_framework_foundry import (
|
||||
FoundryAgent,
|
||||
FoundryChatClient,
|
||||
FoundryChatOptions,
|
||||
FoundryEmbeddingClient,
|
||||
FoundryEmbeddingOptions,
|
||||
FoundryEmbeddingSettings,
|
||||
FoundryEvals,
|
||||
FoundryMemoryProvider,
|
||||
RawFoundryAgent,
|
||||
RawFoundryAgentChatClient,
|
||||
RawFoundryChatClient,
|
||||
RawFoundryEmbeddingClient,
|
||||
evaluate_foundry_target,
|
||||
evaluate_traces,
|
||||
)
|
||||
@@ -27,6 +31,9 @@ __all__ = [
|
||||
"FoundryAgent",
|
||||
"FoundryChatClient",
|
||||
"FoundryChatOptions",
|
||||
"FoundryEmbeddingClient",
|
||||
"FoundryEmbeddingOptions",
|
||||
"FoundryEmbeddingSettings",
|
||||
"FoundryEvals",
|
||||
"FoundryLocalChatOptions",
|
||||
"FoundryLocalClient",
|
||||
@@ -36,6 +43,7 @@ __all__ = [
|
||||
"RawFoundryAgent",
|
||||
"RawFoundryAgentChatClient",
|
||||
"RawFoundryChatClient",
|
||||
"RawFoundryEmbeddingClient",
|
||||
"evaluate_foundry_target",
|
||||
"evaluate_traces",
|
||||
]
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
This module lazily re-exports objects from:
|
||||
- ``agent-framework-copilotstudio``
|
||||
- ``agent-framework-purview``
|
||||
- ``agent-framework-foundry-local``
|
||||
|
||||
Supported classes:
|
||||
- CopilotStudioAgent
|
||||
@@ -20,9 +19,6 @@ Supported classes:
|
||||
- PurviewRequestError
|
||||
- PurviewServiceError
|
||||
- CacheProvider
|
||||
- FoundryLocalChatOptions
|
||||
- FoundryLocalClient
|
||||
- FoundryLocalSettings
|
||||
|
||||
"""
|
||||
|
||||
@@ -43,9 +39,6 @@ _IMPORTS: dict[str, tuple[str, str]] = {
|
||||
"PurviewRequestError": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"PurviewServiceError": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"CacheProvider": ("agent_framework_purview", "agent-framework-purview"),
|
||||
"FoundryLocalChatOptions": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
"FoundryLocalClient": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
"FoundryLocalSettings": ("agent_framework_foundry_local", "agent-framework-foundry-local"),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,6 @@ from agent_framework_copilotstudio import (
|
||||
CopilotStudioAgent,
|
||||
acquire_token,
|
||||
)
|
||||
from agent_framework_foundry_local import (
|
||||
FoundryLocalChatOptions,
|
||||
FoundryLocalClient,
|
||||
FoundryLocalSettings,
|
||||
)
|
||||
from agent_framework_purview import (
|
||||
CacheProvider,
|
||||
PurviewAppLocation,
|
||||
@@ -26,9 +21,6 @@ from agent_framework_purview import (
|
||||
__all__ = [
|
||||
"CacheProvider",
|
||||
"CopilotStudioAgent",
|
||||
"FoundryLocalChatOptions",
|
||||
"FoundryLocalClient",
|
||||
"FoundryLocalSettings",
|
||||
"PurviewAppLocation",
|
||||
"PurviewAuthenticationError",
|
||||
"PurviewChatPolicyMiddleware",
|
||||
|
||||
@@ -35,10 +35,10 @@ all = [
|
||||
"agent-framework-a2a",
|
||||
"agent-framework-ag-ui",
|
||||
"agent-framework-azure-ai-search",
|
||||
"agent-framework-azure-cosmos",
|
||||
"agent-framework-anthropic",
|
||||
"agent-framework-openai",
|
||||
"agent-framework-claude",
|
||||
"agent-framework-azure-ai",
|
||||
"agent-framework-azurefunctions",
|
||||
"agent-framework-bedrock",
|
||||
"agent-framework-chatkit",
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
|
||||
import agent_framework.azure as azure
|
||||
|
||||
|
||||
def test_azure_namespace_exposes_cosmos_history_provider() -> None:
|
||||
assert azure.CosmosHistoryProvider is CosmosHistoryProvider
|
||||
assert "CosmosHistoryProvider" in dir(azure)
|
||||
@@ -481,7 +481,7 @@ services:
|
||||
environment:
|
||||
# OpenAI
|
||||
- OPENAI_API_KEY=\${OPENAI_API_KEY}
|
||||
- OPENAI_CHAT_MODEL=\${OPENAI_CHAT_MODEL:-gpt-4o-mini}
|
||||
- OPENAI_CHAT_COMPLETION_MODEL=\${OPENAI_CHAT_COMPLETION_MODEL:-gpt-4o-mini}
|
||||
# Or Azure OpenAI
|
||||
- AZURE_OPENAI_API_KEY=\${AZURE_OPENAI_API_KEY}
|
||||
- AZURE_OPENAI_ENDPOINT=\${AZURE_OPENAI_ENDPOINT}
|
||||
@@ -514,7 +514,7 @@ az acr build --registry myregistry \\
|
||||
--target-port 8080 \\
|
||||
--ingress 'external' \\
|
||||
--registry-server myregistry.azurecr.io \\
|
||||
--env-vars OPENAI_API_KEY=secretref:openai-key OPENAI_CHAT_MODEL=gpt-4o-mini`})]
|
||||
--env-vars OPENAI_API_KEY=secretref:openai-key OPENAI_CHAT_COMPLETION_MODEL=gpt-4o-mini`})]
|
||||
}), o.jsxs("div", {
|
||||
className: "border-l-2 border-primary pl-3", children: [o.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [o.jsx("div", { className: "w-5 h-5 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs font-bold", children: "5" }), o.jsx("h5", { className: "font-medium text-sm", children: "Get Application URL" })] }), o.jsx("pre", {
|
||||
className: "bg-muted p-2 rounded text-xs overflow-x-auto border mt-2", children: `az containerapp show --name ${r.toLowerCase()}-app \\
|
||||
|
||||
@@ -33,7 +33,7 @@ Then edit `.env` and add your API keys:
|
||||
```bash
|
||||
# For OpenAI (minimum required)
|
||||
OPENAI_API_KEY="your-api-key-here"
|
||||
OPENAI_CHAT_MODEL="gpt-4o-mini"
|
||||
OPENAI_CHAT_COMPLETION_MODEL="gpt-4o-mini"
|
||||
|
||||
# Or for Azure OpenAI
|
||||
AZURE_OPENAI_ENDPOINT="your-endpoint"
|
||||
|
||||
@@ -243,7 +243,7 @@ services:
|
||||
environment:
|
||||
# OpenAI
|
||||
- OPENAI_API_KEY=\${OPENAI_API_KEY}
|
||||
- OPENAI_CHAT_MODEL=\${OPENAI_CHAT_MODEL:-gpt-4o-mini}
|
||||
- OPENAI_CHAT_COMPLETION_MODEL=\${OPENAI_CHAT_COMPLETION_MODEL:-gpt-4o-mini}
|
||||
# Or Azure OpenAI
|
||||
- AZURE_OPENAI_API_KEY=\${AZURE_OPENAI_API_KEY}
|
||||
- AZURE_OPENAI_ENDPOINT=\${AZURE_OPENAI_ENDPOINT}
|
||||
@@ -802,7 +802,7 @@ az acr build --registry myregistry \\
|
||||
--target-port 8080 \\
|
||||
--ingress 'external' \\
|
||||
--registry-server myregistry.azurecr.io \\
|
||||
--env-vars OPENAI_API_KEY=secretref:openai-key OPENAI_CHAT_MODEL=gpt-4o-mini`}
|
||||
--env-vars OPENAI_API_KEY=secretref:openai-key OPENAI_CHAT_COMPLETION_MODEL=gpt-4o-mini`}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Agent Framework Foundry
|
||||
|
||||
This package contains the cloud Azure AI Foundry integrations for Microsoft Agent Framework, including Foundry chat clients, preconfigured Foundry agents, and Foundry memory providers.
|
||||
This package contains the Microsoft Foundry integrations for Microsoft Agent Framework, including Foundry chat clients, preconfigured Foundry agents, Foundry embedding clients, and Foundry memory providers.
|
||||
|
||||
@@ -4,6 +4,12 @@ import importlib.metadata
|
||||
|
||||
from ._agent import FoundryAgent, RawFoundryAgent, RawFoundryAgentChatClient
|
||||
from ._chat_client import FoundryChatClient, FoundryChatOptions, RawFoundryChatClient
|
||||
from ._embedding_client import (
|
||||
FoundryEmbeddingClient,
|
||||
FoundryEmbeddingOptions,
|
||||
FoundryEmbeddingSettings,
|
||||
RawFoundryEmbeddingClient,
|
||||
)
|
||||
from ._foundry_evals import (
|
||||
FoundryEvals,
|
||||
evaluate_foundry_target,
|
||||
@@ -20,11 +26,15 @@ __all__ = [
|
||||
"FoundryAgent",
|
||||
"FoundryChatClient",
|
||||
"FoundryChatOptions",
|
||||
"FoundryEmbeddingClient",
|
||||
"FoundryEmbeddingOptions",
|
||||
"FoundryEmbeddingSettings",
|
||||
"FoundryEvals",
|
||||
"FoundryMemoryProvider",
|
||||
"RawFoundryAgent",
|
||||
"RawFoundryAgentChatClient",
|
||||
"RawFoundryChatClient",
|
||||
"RawFoundryEmbeddingClient",
|
||||
"__version__",
|
||||
"evaluate_foundry_target",
|
||||
"evaluate_traces",
|
||||
|
||||
+51
-51
@@ -28,22 +28,22 @@ else:
|
||||
from typing_extensions import TypeVar # type: ignore # pragma: no cover
|
||||
|
||||
|
||||
logger = logging.getLogger("agent_framework.azure_ai")
|
||||
logger = logging.getLogger("agent_framework.foundry")
|
||||
|
||||
_IMAGE_MEDIA_PREFIXES = ("image/",)
|
||||
|
||||
|
||||
class AzureAIInferenceEmbeddingOptions(EmbeddingGenerationOptions, total=False):
|
||||
"""Azure AI Inference-specific embedding options.
|
||||
class FoundryEmbeddingOptions(EmbeddingGenerationOptions, total=False):
|
||||
"""Foundry inference-specific embedding options.
|
||||
|
||||
Extends EmbeddingGenerationOptions with Azure AI Inference-specific fields.
|
||||
Extends ``EmbeddingGenerationOptions`` with Foundry inference-specific fields.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
from agent_framework_azure_ai import AzureAIInferenceEmbeddingOptions
|
||||
from agent_framework_foundry import FoundryEmbeddingOptions
|
||||
|
||||
options: AzureAIInferenceEmbeddingOptions = {
|
||||
options: FoundryEmbeddingOptions = {
|
||||
"model": "text-embedding-3-small",
|
||||
"dimensions": 1536,
|
||||
"input_type": "document",
|
||||
@@ -68,28 +68,28 @@ class AzureAIInferenceEmbeddingOptions(EmbeddingGenerationOptions, total=False):
|
||||
"""Additional model-specific parameters passed directly to the API."""
|
||||
|
||||
|
||||
AzureAIInferenceEmbeddingOptionsT = TypeVar(
|
||||
"AzureAIInferenceEmbeddingOptionsT",
|
||||
FoundryEmbeddingOptionsT = TypeVar(
|
||||
"FoundryEmbeddingOptionsT",
|
||||
bound=TypedDict, # type: ignore[valid-type]
|
||||
default="AzureAIInferenceEmbeddingOptions",
|
||||
default="FoundryEmbeddingOptions",
|
||||
covariant=True,
|
||||
)
|
||||
|
||||
|
||||
class AzureAIInferenceEmbeddingSettings(TypedDict, total=False):
|
||||
"""Azure AI Inference embedding settings."""
|
||||
class FoundryEmbeddingSettings(TypedDict, total=False):
|
||||
"""Foundry inference embedding settings."""
|
||||
|
||||
endpoint: str | None
|
||||
api_key: str | None
|
||||
models_endpoint: str | None
|
||||
models_api_key: str | None
|
||||
embedding_model: str | None
|
||||
image_embedding_model: str | None
|
||||
|
||||
|
||||
class RawAzureAIInferenceEmbeddingClient(
|
||||
BaseEmbeddingClient[Content | str, list[float], AzureAIInferenceEmbeddingOptionsT],
|
||||
Generic[AzureAIInferenceEmbeddingOptionsT],
|
||||
class RawFoundryEmbeddingClient(
|
||||
BaseEmbeddingClient[Content | str, list[float], FoundryEmbeddingOptionsT],
|
||||
Generic[FoundryEmbeddingOptionsT],
|
||||
):
|
||||
"""Raw Azure AI Inference embedding client without telemetry.
|
||||
"""Raw Foundry embedding client without telemetry.
|
||||
|
||||
Accepts both text (``str``) and image (``Content``) inputs. Text and image
|
||||
inputs within a single batch are separated and dispatched to
|
||||
@@ -98,14 +98,14 @@ class RawAzureAIInferenceEmbeddingClient(
|
||||
|
||||
Keyword Args:
|
||||
model: The text embedding model (e.g. "text-embedding-3-small").
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_EMBEDDING_MODEL.
|
||||
Can also be set via environment variable FOUNDRY_EMBEDDING_MODEL.
|
||||
image_model: The image embedding model (e.g. "Cohere-embed-v3-english").
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL.
|
||||
Can also be set via environment variable FOUNDRY_IMAGE_EMBEDDING_MODEL.
|
||||
Falls back to ``model`` if not provided.
|
||||
endpoint: The Azure AI Inference endpoint URL.
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_ENDPOINT.
|
||||
endpoint: The Foundry inference endpoint URL.
|
||||
Can also be set via environment variable FOUNDRY_MODELS_ENDPOINT.
|
||||
api_key: API key for authentication.
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_API_KEY.
|
||||
Can also be set via environment variable FOUNDRY_MODELS_API_KEY.
|
||||
text_client: Optional pre-configured ``EmbeddingsClient``.
|
||||
image_client: Optional pre-configured ``ImageEmbeddingsClient``.
|
||||
credential: Optional ``AzureKeyCredential`` or token credential. If not provided,
|
||||
@@ -128,13 +128,13 @@ class RawAzureAIInferenceEmbeddingClient(
|
||||
env_file_path: str | None = None,
|
||||
env_file_encoding: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize a raw Azure AI Inference embedding client."""
|
||||
"""Initialize a raw Foundry embedding client."""
|
||||
settings = load_settings(
|
||||
AzureAIInferenceEmbeddingSettings,
|
||||
env_prefix="AZURE_AI_INFERENCE_",
|
||||
required_fields=["endpoint", "embedding_model"],
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
FoundryEmbeddingSettings,
|
||||
env_prefix="FOUNDRY_",
|
||||
required_fields=["models_endpoint", "embedding_model"],
|
||||
models_endpoint=endpoint,
|
||||
models_api_key=api_key,
|
||||
embedding_model=model,
|
||||
image_embedding_model=image_model,
|
||||
env_file_path=env_file_path,
|
||||
@@ -143,10 +143,10 @@ class RawAzureAIInferenceEmbeddingClient(
|
||||
|
||||
self.model = settings["embedding_model"] # type: ignore[reportTypedDictNotRequiredAccess]
|
||||
self.image_model: str = settings.get("image_embedding_model") or self.model # type: ignore[assignment]
|
||||
resolved_endpoint = settings["endpoint"] # type: ignore[reportTypedDictNotRequiredAccess]
|
||||
resolved_endpoint = settings["models_endpoint"] # type: ignore[reportTypedDictNotRequiredAccess]
|
||||
|
||||
if credential is None and settings.get("api_key"):
|
||||
credential = AzureKeyCredential(settings["api_key"]) # type: ignore[arg-type]
|
||||
if credential is None and settings.get("models_api_key"):
|
||||
credential = AzureKeyCredential(settings["models_api_key"]) # type: ignore[arg-type]
|
||||
|
||||
if credential is None and text_client is None and image_client is None:
|
||||
raise ValueError("Either 'api_key', 'credential', or pre-configured client(s) must be provided.")
|
||||
@@ -169,7 +169,7 @@ class RawAzureAIInferenceEmbeddingClient(
|
||||
with suppress(Exception):
|
||||
await self._image_client.close()
|
||||
|
||||
async def __aenter__(self) -> RawAzureAIInferenceEmbeddingClient[AzureAIInferenceEmbeddingOptionsT]:
|
||||
async def __aenter__(self) -> RawFoundryEmbeddingClient[FoundryEmbeddingOptionsT]:
|
||||
"""Enter the async context manager."""
|
||||
return self
|
||||
|
||||
@@ -185,8 +185,8 @@ class RawAzureAIInferenceEmbeddingClient(
|
||||
self,
|
||||
values: Sequence[Content | str],
|
||||
*,
|
||||
options: AzureAIInferenceEmbeddingOptionsT | None = None,
|
||||
) -> GeneratedEmbeddings[list[float], AzureAIInferenceEmbeddingOptionsT]:
|
||||
options: FoundryEmbeddingOptionsT | None = None,
|
||||
) -> GeneratedEmbeddings[list[float], FoundryEmbeddingOptionsT]:
|
||||
"""Generate embeddings for text and/or image inputs.
|
||||
|
||||
Text inputs (``str`` or ``Content`` with ``type="text"``) are sent to the
|
||||
@@ -310,12 +310,12 @@ class RawAzureAIInferenceEmbeddingClient(
|
||||
) # type: ignore[reportReturnType]
|
||||
|
||||
|
||||
class AzureAIInferenceEmbeddingClient(
|
||||
EmbeddingTelemetryLayer[Content | str, list[float], AzureAIInferenceEmbeddingOptionsT],
|
||||
RawAzureAIInferenceEmbeddingClient[AzureAIInferenceEmbeddingOptionsT],
|
||||
Generic[AzureAIInferenceEmbeddingOptionsT],
|
||||
class FoundryEmbeddingClient(
|
||||
EmbeddingTelemetryLayer[Content | str, list[float], FoundryEmbeddingOptionsT],
|
||||
RawFoundryEmbeddingClient[FoundryEmbeddingOptionsT],
|
||||
Generic[FoundryEmbeddingOptionsT],
|
||||
):
|
||||
"""Azure AI Inference embedding client with telemetry support.
|
||||
"""Foundry embedding client with telemetry support.
|
||||
|
||||
Supports both text and image inputs in a single client. Pass plain strings
|
||||
or ``Content`` instances created with ``Content.from_text()`` or
|
||||
@@ -323,14 +323,14 @@ class AzureAIInferenceEmbeddingClient(
|
||||
|
||||
Keyword Args:
|
||||
model: The text embedding model (e.g. "text-embedding-3-small").
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_EMBEDDING_MODEL.
|
||||
Can also be set via environment variable FOUNDRY_EMBEDDING_MODEL.
|
||||
image_model: The image embedding model
|
||||
(e.g. "Cohere-embed-v3-english"). Can also be set via environment variable
|
||||
AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL. Falls back to ``model``.
|
||||
endpoint: The Azure AI Inference endpoint URL.
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_ENDPOINT.
|
||||
FOUNDRY_IMAGE_EMBEDDING_MODEL. Falls back to ``model``.
|
||||
endpoint: The Foundry inference endpoint URL.
|
||||
Can also be set via environment variable FOUNDRY_MODELS_ENDPOINT.
|
||||
api_key: API key for authentication.
|
||||
Can also be set via environment variable AZURE_AI_INFERENCE_API_KEY.
|
||||
Can also be set via environment variable FOUNDRY_MODELS_API_KEY.
|
||||
text_client: Optional pre-configured ``EmbeddingsClient``.
|
||||
image_client: Optional pre-configured ``ImageEmbeddingsClient``.
|
||||
credential: Optional ``AzureKeyCredential`` or token credential.
|
||||
@@ -341,14 +341,14 @@ class AzureAIInferenceEmbeddingClient(
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
from agent_framework_azure_ai import AzureAIInferenceEmbeddingClient
|
||||
from agent_framework_foundry import FoundryEmbeddingClient
|
||||
|
||||
# Using environment variables
|
||||
# Set AZURE_AI_INFERENCE_ENDPOINT=https://your-endpoint.inference.ai.azure.com
|
||||
# Set AZURE_AI_INFERENCE_API_KEY=your-key
|
||||
# Set AZURE_AI_INFERENCE_EMBEDDING_MODEL=text-embedding-3-small
|
||||
# Set AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL=Cohere-embed-v3-english
|
||||
client = AzureAIInferenceEmbeddingClient()
|
||||
# Set FOUNDRY_MODELS_ENDPOINT=https://your-endpoint.inference.ai.azure.com
|
||||
# Set FOUNDRY_MODELS_API_KEY=your-key
|
||||
# Set FOUNDRY_EMBEDDING_MODEL=text-embedding-3-small
|
||||
# Set FOUNDRY_IMAGE_EMBEDDING_MODEL=Cohere-embed-v3-english
|
||||
client = FoundryEmbeddingClient()
|
||||
|
||||
# Text embeddings
|
||||
result = await client.get_embeddings(["Hello, world!"])
|
||||
@@ -380,7 +380,7 @@ class AzureAIInferenceEmbeddingClient(
|
||||
env_file_path: str | None = None,
|
||||
env_file_encoding: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize an Azure AI Inference embedding client."""
|
||||
"""Initialize a Foundry embedding client."""
|
||||
super().__init__(
|
||||
model=model,
|
||||
image_model=image_model,
|
||||
@@ -25,6 +25,7 @@ classifiers = [
|
||||
dependencies = [
|
||||
"agent-framework-core>=1.0.0rc6",
|
||||
"agent-framework-openai>=1.0.0rc6",
|
||||
"azure-ai-inference>=1.0.0b9,<1.0.0b10",
|
||||
"azure-ai-projects>=2.0.0,<3.0",
|
||||
]
|
||||
|
||||
|
||||
+55
-57
@@ -10,10 +10,10 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
import pytest
|
||||
from agent_framework import Content
|
||||
|
||||
from agent_framework_azure_ai import (
|
||||
AzureAIInferenceEmbeddingClient,
|
||||
AzureAIInferenceEmbeddingOptions,
|
||||
RawAzureAIInferenceEmbeddingClient,
|
||||
from agent_framework_foundry import (
|
||||
FoundryEmbeddingClient,
|
||||
FoundryEmbeddingOptions,
|
||||
RawFoundryEmbeddingClient,
|
||||
)
|
||||
|
||||
|
||||
@@ -57,9 +57,9 @@ def mock_image_client() -> AsyncMock:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def raw_client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> RawAzureAIInferenceEmbeddingClient[Any]:
|
||||
"""Create a RawAzureAIInferenceEmbeddingClient with mocked SDK clients."""
|
||||
return RawAzureAIInferenceEmbeddingClient(
|
||||
def raw_client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> RawFoundryEmbeddingClient[Any]:
|
||||
"""Create a RawFoundryEmbeddingClient with mocked SDK clients."""
|
||||
return RawFoundryEmbeddingClient(
|
||||
model="test-model",
|
||||
endpoint="https://test.inference.ai.azure.com",
|
||||
api_key="test-key",
|
||||
@@ -69,9 +69,9 @@ def raw_client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> Raw
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> AzureAIInferenceEmbeddingClient[Any]:
|
||||
"""Create an AzureAIInferenceEmbeddingClient with mocked SDK clients."""
|
||||
return AzureAIInferenceEmbeddingClient(
|
||||
def client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> FoundryEmbeddingClient[Any]:
|
||||
"""Create a FoundryEmbeddingClient with mocked SDK clients."""
|
||||
return FoundryEmbeddingClient(
|
||||
model="test-model",
|
||||
endpoint="https://test.inference.ai.azure.com",
|
||||
api_key="test-key",
|
||||
@@ -80,11 +80,11 @@ def client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> AzureAI
|
||||
)
|
||||
|
||||
|
||||
class TestRawAzureAIInferenceEmbeddingClient:
|
||||
"""Tests for the raw Azure AI Inference embedding client."""
|
||||
class TestRawFoundryEmbeddingClient:
|
||||
"""Tests for the raw Foundry embedding client."""
|
||||
|
||||
async def test_text_embeddings(
|
||||
self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
self, raw_client: RawFoundryEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
) -> None:
|
||||
"""Text inputs are dispatched to the text client."""
|
||||
result = await raw_client.get_embeddings(["hello", "world"])
|
||||
@@ -94,7 +94,7 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
assert call_kwargs.kwargs["model"] == "test-model"
|
||||
|
||||
async def test_text_content_embeddings(
|
||||
self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
self, raw_client: RawFoundryEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
) -> None:
|
||||
"""Content.from_text() inputs are dispatched to the text client."""
|
||||
text_content = Content.from_text("hello")
|
||||
@@ -105,7 +105,7 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
assert call_kwargs.kwargs["input"] == ["hello"]
|
||||
|
||||
async def test_image_content_embeddings(
|
||||
self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_image_client: AsyncMock
|
||||
self, raw_client: RawFoundryEmbeddingClient[Any], mock_image_client: AsyncMock
|
||||
) -> None:
|
||||
"""Image Content inputs are dispatched to the image client."""
|
||||
image_content = Content.from_data(data=b"\x89PNG", media_type="image/png")
|
||||
@@ -119,7 +119,7 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
|
||||
async def test_mixed_text_and_image(
|
||||
self,
|
||||
raw_client: RawAzureAIInferenceEmbeddingClient[Any],
|
||||
raw_client: RawFoundryEmbeddingClient[Any],
|
||||
mock_text_client: AsyncMock,
|
||||
mock_image_client: AsyncMock,
|
||||
) -> None:
|
||||
@@ -138,16 +138,16 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
image_call = mock_image_client.embed.call_args
|
||||
assert len(image_call.kwargs["input"]) == 1
|
||||
|
||||
async def test_empty_input(self, raw_client: RawAzureAIInferenceEmbeddingClient[Any]) -> None:
|
||||
async def test_empty_input(self, raw_client: RawFoundryEmbeddingClient[Any]) -> None:
|
||||
"""Empty input returns empty result."""
|
||||
result = await raw_client.get_embeddings([])
|
||||
assert len(result) == 0
|
||||
|
||||
async def test_options_passed_through(
|
||||
self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
self, raw_client: RawFoundryEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
) -> None:
|
||||
"""Options are passed through to the SDK."""
|
||||
options: AzureAIInferenceEmbeddingOptions = {
|
||||
options: FoundryEmbeddingOptions = {
|
||||
"dimensions": 512,
|
||||
"input_type": "document",
|
||||
"encoding_format": "float",
|
||||
@@ -160,23 +160,23 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
assert call_kwargs.kwargs["encoding_format"] == "float"
|
||||
|
||||
async def test_model_override_in_options(
|
||||
self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
self, raw_client: RawFoundryEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
) -> None:
|
||||
"""model in options overrides the default."""
|
||||
options: AzureAIInferenceEmbeddingOptions = {"model": "custom-model"}
|
||||
options: FoundryEmbeddingOptions = {"model": "custom-model"}
|
||||
await raw_client.get_embeddings(["hello"], options=options)
|
||||
|
||||
call_kwargs = mock_text_client.embed.call_args
|
||||
assert call_kwargs.kwargs["model"] == "custom-model"
|
||||
|
||||
async def test_unsupported_content_type_raises(self, raw_client: RawAzureAIInferenceEmbeddingClient[Any]) -> None:
|
||||
async def test_unsupported_content_type_raises(self, raw_client: RawFoundryEmbeddingClient[Any]) -> None:
|
||||
"""Non-text, non-image Content raises ValueError."""
|
||||
error_content = Content("error", message="fail")
|
||||
with pytest.raises(ValueError, match="Unsupported Content type"):
|
||||
await raw_client.get_embeddings([error_content])
|
||||
|
||||
async def test_usage_metadata(
|
||||
self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
self, raw_client: RawFoundryEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
) -> None:
|
||||
"""Usage metadata is populated from the response."""
|
||||
mock_text_client.embed.return_value = _make_embed_response([[0.1, 0.2]], prompt_tokens=42)
|
||||
@@ -184,7 +184,7 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
assert result.usage is not None
|
||||
assert result.usage["input_token_count"] == 42
|
||||
|
||||
def test_service_url(self, raw_client: RawAzureAIInferenceEmbeddingClient[Any]) -> None:
|
||||
def test_service_url(self, raw_client: RawFoundryEmbeddingClient[Any]) -> None:
|
||||
"""service_url returns the configured endpoint."""
|
||||
assert raw_client.service_url() == "https://test.inference.ai.azure.com"
|
||||
|
||||
@@ -194,15 +194,15 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"AZURE_AI_INFERENCE_ENDPOINT": "https://env.inference.ai.azure.com",
|
||||
"AZURE_AI_INFERENCE_API_KEY": "env-key",
|
||||
"AZURE_AI_INFERENCE_EMBEDDING_MODEL": "env-model",
|
||||
"FOUNDRY_MODELS_ENDPOINT": "https://env.inference.ai.azure.com",
|
||||
"FOUNDRY_MODELS_API_KEY": "env-key",
|
||||
"FOUNDRY_EMBEDDING_MODEL": "env-model",
|
||||
},
|
||||
),
|
||||
patch("agent_framework_azure_ai._embedding_client.EmbeddingsClient"),
|
||||
patch("agent_framework_azure_ai._embedding_client.ImageEmbeddingsClient"),
|
||||
patch("agent_framework_foundry._embedding_client.EmbeddingsClient"),
|
||||
patch("agent_framework_foundry._embedding_client.ImageEmbeddingsClient"),
|
||||
):
|
||||
client = RawAzureAIInferenceEmbeddingClient()
|
||||
client = RawFoundryEmbeddingClient()
|
||||
assert client.model == "env-model"
|
||||
assert client.image_model == "env-model" # falls back to model
|
||||
|
||||
@@ -212,22 +212,22 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"AZURE_AI_INFERENCE_ENDPOINT": "https://env.inference.ai.azure.com",
|
||||
"AZURE_AI_INFERENCE_API_KEY": "env-key",
|
||||
"AZURE_AI_INFERENCE_EMBEDDING_MODEL": "text-model",
|
||||
"AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL": "image-model",
|
||||
"FOUNDRY_MODELS_ENDPOINT": "https://env.inference.ai.azure.com",
|
||||
"FOUNDRY_MODELS_API_KEY": "env-key",
|
||||
"FOUNDRY_EMBEDDING_MODEL": "text-model",
|
||||
"FOUNDRY_IMAGE_EMBEDDING_MODEL": "image-model",
|
||||
},
|
||||
),
|
||||
patch("agent_framework_azure_ai._embedding_client.EmbeddingsClient"),
|
||||
patch("agent_framework_azure_ai._embedding_client.ImageEmbeddingsClient"),
|
||||
patch("agent_framework_foundry._embedding_client.EmbeddingsClient"),
|
||||
patch("agent_framework_foundry._embedding_client.ImageEmbeddingsClient"),
|
||||
):
|
||||
client = RawAzureAIInferenceEmbeddingClient()
|
||||
client = RawFoundryEmbeddingClient()
|
||||
assert client.model == "text-model"
|
||||
assert client.image_model == "image-model"
|
||||
|
||||
def test_image_model_explicit(self, mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> None:
|
||||
"""image_model can be set explicitly."""
|
||||
client = RawAzureAIInferenceEmbeddingClient(
|
||||
client = RawFoundryEmbeddingClient(
|
||||
model="text-model",
|
||||
image_model="image-model",
|
||||
endpoint="https://test.inference.ai.azure.com",
|
||||
@@ -242,7 +242,7 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
self, mock_text_client: AsyncMock, mock_image_client: AsyncMock
|
||||
) -> None:
|
||||
"""image_model is passed to the image client embed call."""
|
||||
client = RawAzureAIInferenceEmbeddingClient(
|
||||
client = RawFoundryEmbeddingClient(
|
||||
model="text-model",
|
||||
image_model="image-model",
|
||||
endpoint="https://test.inference.ai.azure.com",
|
||||
@@ -256,12 +256,10 @@ class TestRawAzureAIInferenceEmbeddingClient:
|
||||
assert call_kwargs.kwargs["model"] == "image-model"
|
||||
|
||||
|
||||
class TestAzureAIInferenceEmbeddingClient:
|
||||
"""Tests for the telemetry-enabled Azure AI Inference embedding client."""
|
||||
class TestFoundryEmbeddingClient:
|
||||
"""Tests for the telemetry-enabled Foundry embedding client."""
|
||||
|
||||
async def test_text_embeddings(
|
||||
self, client: AzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock
|
||||
) -> None:
|
||||
async def test_text_embeddings(self, client: FoundryEmbeddingClient[Any], mock_text_client: AsyncMock) -> None:
|
||||
"""Text embeddings work through the telemetry layer."""
|
||||
result = await client.get_embeddings(["hello"])
|
||||
assert len(result) == 1
|
||||
@@ -269,11 +267,11 @@ class TestAzureAIInferenceEmbeddingClient:
|
||||
|
||||
async def test_otel_provider_name_default(self) -> None:
|
||||
"""Default OTEL provider name is azure.ai.inference."""
|
||||
assert AzureAIInferenceEmbeddingClient.OTEL_PROVIDER_NAME == "azure.ai.inference"
|
||||
assert FoundryEmbeddingClient.OTEL_PROVIDER_NAME == "azure.ai.inference"
|
||||
|
||||
async def test_otel_provider_name_override(self, mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> None:
|
||||
"""OTEL provider name can be overridden."""
|
||||
client = AzureAIInferenceEmbeddingClient(
|
||||
client = FoundryEmbeddingClient(
|
||||
model="test-model",
|
||||
endpoint="https://test.inference.ai.azure.com",
|
||||
api_key="test-key",
|
||||
@@ -284,32 +282,32 @@ class TestAzureAIInferenceEmbeddingClient:
|
||||
assert client.otel_provider_name == "custom-provider"
|
||||
|
||||
|
||||
_SKIP_REASON = "Azure AI Inference integration tests disabled"
|
||||
_SKIP_REASON = "Foundry inference integration tests disabled"
|
||||
|
||||
|
||||
def _integration_tests_enabled() -> bool:
|
||||
def _foundry_integration_tests_enabled() -> bool:
|
||||
return bool(
|
||||
os.environ.get("AZURE_AI_INFERENCE_ENDPOINT")
|
||||
and os.environ.get("AZURE_AI_INFERENCE_API_KEY")
|
||||
and os.environ.get("AZURE_AI_INFERENCE_EMBEDDING_MODEL")
|
||||
os.environ.get("FOUNDRY_MODELS_ENDPOINT")
|
||||
and os.environ.get("FOUNDRY_MODELS_API_KEY")
|
||||
and os.environ.get("FOUNDRY_EMBEDDING_MODEL")
|
||||
)
|
||||
|
||||
|
||||
skip_if_azure_ai_inference_integration_tests_disabled = pytest.mark.skipif(
|
||||
not _integration_tests_enabled(),
|
||||
skip_if_foundry_inference_integration_tests_disabled = pytest.mark.skipif(
|
||||
not _foundry_integration_tests_enabled(),
|
||||
reason=_SKIP_REASON,
|
||||
)
|
||||
|
||||
|
||||
class TestAzureAIInferenceEmbeddingIntegration:
|
||||
"""Integration tests requiring a live Azure AI Inference endpoint."""
|
||||
class TestFoundryEmbeddingIntegration:
|
||||
"""Integration tests requiring a live Foundry inference endpoint."""
|
||||
|
||||
@pytest.mark.flaky
|
||||
@pytest.mark.integration
|
||||
@skip_if_azure_ai_inference_integration_tests_disabled
|
||||
@skip_if_foundry_inference_integration_tests_disabled
|
||||
async def test_text_embedding_live(self) -> None:
|
||||
"""Generate text embeddings against a live endpoint."""
|
||||
client = AzureAIInferenceEmbeddingClient()
|
||||
client = FoundryEmbeddingClient()
|
||||
result = await client.get_embeddings(["Hello, world!"])
|
||||
assert len(result) == 1
|
||||
assert len(result[0].vector) > 0
|
||||
@@ -7,7 +7,7 @@ configured for GAIA benchmark tasks using the OpenAI Responses API.
|
||||
|
||||
Required Environment Variables:
|
||||
OPENAI_API_KEY: Your OpenAI API key
|
||||
OPENAI_RESPONSES_MODEL: Model to use with Responses API (e.g., gpt-4o, gpt-4o-mini)
|
||||
OPENAI_CHAT_MODEL: Model to use with Responses API (e.g., gpt-4o, gpt-4o-mini)
|
||||
|
||||
Optional Environment Variables:
|
||||
OPENAI_BASE_URL: Custom API base URL if using a proxy or compatible service
|
||||
@@ -19,7 +19,7 @@ Authentication:
|
||||
|
||||
Example:
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
export OPENAI_RESPONSES_MODEL="gpt-4o"
|
||||
export OPENAI_CHAT_MODEL="gpt-4o"
|
||||
"""
|
||||
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
@@ -36,16 +36,20 @@ These variables are used when the client is configured for OpenAI:
|
||||
| `OPENAI_ORG_ID` | OpenAI organization ID |
|
||||
| `OPENAI_BASE_URL` | Custom OpenAI-compatible base URL |
|
||||
| `OPENAI_MODEL` | Generic fallback model |
|
||||
| `OPENAI_RESPONSES_MODEL` | Preferred model for `OpenAIChatClient` |
|
||||
| `OPENAI_CHAT_MODEL` | Preferred model for `OpenAIChatCompletionClient` |
|
||||
| `OPENAI_CHAT_MODEL` | Preferred model for `OpenAIChatClient` |
|
||||
| `OPENAI_CHAT_COMPLETION_MODEL` | Preferred model for `OpenAIChatCompletionClient` |
|
||||
| `OPENAI_EMBEDDING_MODEL` | Preferred model for `OpenAIEmbeddingClient` |
|
||||
|
||||
Model lookup order:
|
||||
|
||||
- `OpenAIChatClient`: `OPENAI_RESPONSES_MODEL` -> `OPENAI_MODEL`
|
||||
- `OpenAIChatCompletionClient`: `OPENAI_CHAT_MODEL` -> `OPENAI_MODEL`
|
||||
- `OpenAIChatClient`: `OPENAI_CHAT_MODEL` -> `OPENAI_MODEL`
|
||||
- `OpenAIChatCompletionClient`: `OPENAI_CHAT_COMPLETION_MODEL` -> `OPENAI_MODEL`
|
||||
- `OpenAIEmbeddingClient`: `OPENAI_EMBEDDING_MODEL` -> `OPENAI_MODEL`
|
||||
|
||||
These model variables are only consulted when you do not pass `model=` directly. In other words,
|
||||
`OpenAIChatClient(model="...")` ignores `OPENAI_CHAT_MODEL`, and
|
||||
`OpenAIChatCompletionClient(model="...")` ignores `OPENAI_CHAT_COMPLETION_MODEL`.
|
||||
|
||||
### Azure OpenAI
|
||||
|
||||
These variables are used when the client is configured for Azure OpenAI:
|
||||
@@ -57,16 +61,19 @@ These variables are used when the client is configured for Azure OpenAI:
|
||||
| `AZURE_OPENAI_API_KEY` | Azure OpenAI API key |
|
||||
| `AZURE_OPENAI_API_VERSION` | Azure OpenAI API version |
|
||||
| `AZURE_OPENAI_MODEL` | Generic fallback deployment |
|
||||
| `AZURE_OPENAI_RESPONSES_MODEL` | Preferred deployment for `OpenAIChatClient` |
|
||||
| `AZURE_OPENAI_CHAT_MODEL` | Preferred deployment for `OpenAIChatCompletionClient` |
|
||||
| `AZURE_OPENAI_CHAT_MODEL` | Preferred deployment for `OpenAIChatClient` |
|
||||
| `AZURE_OPENAI_CHAT_COMPLETION_MODEL` | Preferred deployment for `OpenAIChatCompletionClient` |
|
||||
| `AZURE_OPENAI_EMBEDDING_MODEL` | Preferred deployment for `OpenAIEmbeddingClient` |
|
||||
|
||||
Deployment lookup order:
|
||||
|
||||
- `OpenAIChatClient`: `AZURE_OPENAI_RESPONSES_MODEL` -> `AZURE_OPENAI_MODEL`
|
||||
- `OpenAIChatCompletionClient`: `AZURE_OPENAI_CHAT_MODEL` -> `AZURE_OPENAI_MODEL`
|
||||
- `OpenAIChatClient`: `AZURE_OPENAI_CHAT_MODEL` -> `AZURE_OPENAI_MODEL`
|
||||
- `OpenAIChatCompletionClient`: `AZURE_OPENAI_CHAT_COMPLETION_MODEL` -> `AZURE_OPENAI_MODEL`
|
||||
- `OpenAIEmbeddingClient`: `AZURE_OPENAI_EMBEDDING_MODEL` -> `AZURE_OPENAI_MODEL`
|
||||
|
||||
For Azure routing, the same rule applies: the client-specific deployment variable is checked first,
|
||||
then the generic `AZURE_OPENAI_MODEL` fallback. Passing `model=` overrides both environment variables.
|
||||
|
||||
When both OpenAI and Azure environment variables are present, the generic clients prefer OpenAI
|
||||
when `OPENAI_API_KEY` is configured. To use Azure explicitly, pass `azure_endpoint` or
|
||||
`credential`.
|
||||
|
||||
@@ -289,7 +289,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_RESPONSES_MODEL`` and then ``OPENAI_MODEL``.
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL``.
|
||||
api_key: API key. When not provided explicitly, the constructor reads
|
||||
``OPENAI_API_KEY``. A callable API key is also supported.
|
||||
org_id: OpenAI organization ID. When not provided explicitly, the constructor reads
|
||||
@@ -331,7 +331,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``AZURE_OPENAI_RESPONSES_MODEL`` and then
|
||||
reads ``AZURE_OPENAI_CHAT_MODEL`` and then
|
||||
``AZURE_OPENAI_MODEL``.
|
||||
azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor
|
||||
reads ``AZURE_OPENAI_ENDPOINT``.
|
||||
@@ -380,8 +380,8 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_RESPONSES_MODEL`` and then ``OPENAI_MODEL`` for OpenAI,
|
||||
or ``AZURE_OPENAI_RESPONSES_MODEL`` and then ``AZURE_OPENAI_MODEL`` for Azure.
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL`` for OpenAI,
|
||||
or ``AZURE_OPENAI_CHAT_MODEL`` and then ``AZURE_OPENAI_MODEL`` for Azure.
|
||||
api_key: API key override. For OpenAI this maps to ``OPENAI_API_KEY``.
|
||||
For Azure this can be used instead of ``AZURE_OPENAI_API_KEY`` for key
|
||||
auth. A callable token provider is also accepted for backwards compatibility,
|
||||
@@ -418,10 +418,10 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
2. Explicit OpenAI API key or ``OPENAI_API_KEY``
|
||||
3. Azure environment fallback
|
||||
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_RESPONSES_MODEL``,
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_CHAT_MODEL``,
|
||||
``OPENAI_MODEL``, ``OPENAI_ORG_ID``, and ``OPENAI_BASE_URL``. Azure routing
|
||||
reads ``AZURE_OPENAI_ENDPOINT``, ``AZURE_OPENAI_BASE_URL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_RESPONSES_MODEL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_MODEL``,
|
||||
``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``.
|
||||
"""
|
||||
settings, client, use_azure_client = load_openai_service_settings(
|
||||
@@ -437,8 +437,8 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
client=async_client,
|
||||
env_file_path=env_file_path,
|
||||
env_file_encoding=env_file_encoding,
|
||||
openai_model_fields=("responses_model", "model"),
|
||||
azure_model_fields=("responses_model", "model"),
|
||||
openai_model_fields=("chat_model", "model"),
|
||||
azure_model_fields=("chat_model", "model"),
|
||||
responses_mode=True,
|
||||
)
|
||||
|
||||
@@ -2501,7 +2501,7 @@ class OpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_RESPONSES_MODEL`` and then ``OPENAI_MODEL``.
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL``.
|
||||
api_key: API key. When not provided explicitly, the constructor reads
|
||||
``OPENAI_API_KEY``. A callable API key is also supported.
|
||||
org_id: OpenAI organization ID. When not provided explicitly, the constructor reads
|
||||
@@ -2547,7 +2547,7 @@ class OpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``AZURE_OPENAI_RESPONSES_MODEL`` and then
|
||||
reads ``AZURE_OPENAI_CHAT_MODEL`` and then
|
||||
``AZURE_OPENAI_MODEL``.
|
||||
azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor
|
||||
reads ``AZURE_OPENAI_ENDPOINT``.
|
||||
@@ -2600,8 +2600,8 @@ class OpenAIChatClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_RESPONSES_MODEL`` and then ``OPENAI_MODEL`` for OpenAI
|
||||
routing, or ``AZURE_OPENAI_RESPONSES_MODEL`` and then
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL`` for OpenAI
|
||||
routing, or ``AZURE_OPENAI_CHAT_MODEL`` and then
|
||||
``AZURE_OPENAI_MODEL`` for Azure routing.
|
||||
api_key: API key override. For OpenAI routing this maps to ``OPENAI_API_KEY``.
|
||||
For Azure routing this can be used instead of ``AZURE_OPENAI_API_KEY`` for key
|
||||
@@ -2641,10 +2641,10 @@ class OpenAIChatClient( # type: ignore[misc]
|
||||
2. Explicit OpenAI API key or ``OPENAI_API_KEY``
|
||||
3. Azure environment fallback
|
||||
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_RESPONSES_MODEL``,
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_CHAT_MODEL``,
|
||||
``OPENAI_MODEL``, ``OPENAI_ORG_ID``, and ``OPENAI_BASE_URL``. Azure routing
|
||||
reads ``AZURE_OPENAI_ENDPOINT``, ``AZURE_OPENAI_BASE_URL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_RESPONSES_MODEL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_MODEL``,
|
||||
``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -203,7 +203,7 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL``.
|
||||
reads ``OPENAI_CHAT_COMPLETION_MODEL`` and then ``OPENAI_MODEL``.
|
||||
api_key: API key. When not provided explicitly, the constructor reads
|
||||
``OPENAI_API_KEY``. A callable API key is also supported.
|
||||
org_id: OpenAI organization ID. When not provided explicitly, the constructor reads
|
||||
@@ -245,7 +245,7 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``AZURE_OPENAI_CHAT_MODEL`` and then
|
||||
reads ``AZURE_OPENAI_CHAT_COMPLETION_MODEL`` and then
|
||||
``AZURE_OPENAI_MODEL``.
|
||||
azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor
|
||||
reads ``AZURE_OPENAI_ENDPOINT``.
|
||||
@@ -294,8 +294,8 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL`` for OpenAI routing,
|
||||
or ``AZURE_OPENAI_CHAT_MODEL`` and then ``AZURE_OPENAI_MODEL`` for Azure routing.
|
||||
reads ``OPENAI_CHAT_COMPLETION_MODEL`` and then ``OPENAI_MODEL`` for OpenAI routing,
|
||||
or ``AZURE_OPENAI_CHAT_COMPLETION_MODEL`` and then ``AZURE_OPENAI_MODEL`` for Azure routing.
|
||||
api_key: API key override. For OpenAI routing this maps to ``OPENAI_API_KEY``.
|
||||
For Azure routing this can be used instead of ``AZURE_OPENAI_API_KEY`` for key
|
||||
auth. A callable token provider is also accepted for backwards compatibility,
|
||||
@@ -332,10 +332,10 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc]
|
||||
2. Explicit OpenAI API key or ``OPENAI_API_KEY``
|
||||
3. Azure environment fallback
|
||||
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_CHAT_MODEL``,
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_CHAT_COMPLETION_MODEL``,
|
||||
``OPENAI_MODEL``, ``OPENAI_ORG_ID``, and ``OPENAI_BASE_URL``. Azure routing
|
||||
reads ``AZURE_OPENAI_ENDPOINT``, ``AZURE_OPENAI_BASE_URL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_MODEL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_COMPLETION_MODEL``,
|
||||
``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``.
|
||||
"""
|
||||
settings, client, use_azure_client = load_openai_service_settings(
|
||||
@@ -351,8 +351,8 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc]
|
||||
client=async_client,
|
||||
env_file_path=env_file_path,
|
||||
env_file_encoding=env_file_encoding,
|
||||
openai_model_fields=("chat_model", "model"),
|
||||
azure_model_fields=("chat_model", "model"),
|
||||
openai_model_fields=("chat_completion_model", "model"),
|
||||
azure_model_fields=("chat_completion_model", "model"),
|
||||
)
|
||||
|
||||
self.client = client
|
||||
@@ -1048,7 +1048,7 @@ class OpenAIChatCompletionClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL``.
|
||||
reads ``OPENAI_CHAT_COMPLETION_MODEL`` and then ``OPENAI_MODEL``.
|
||||
api_key: API key. When not provided explicitly, the constructor reads
|
||||
``OPENAI_API_KEY``. A callable API key is also supported.
|
||||
org_id: OpenAI organization ID. When not provided explicitly, the constructor reads
|
||||
@@ -1088,7 +1088,7 @@ class OpenAIChatCompletionClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``AZURE_OPENAI_CHAT_MODEL`` and then
|
||||
reads ``AZURE_OPENAI_CHAT_COMPLETION_MODEL`` and then
|
||||
``AZURE_OPENAI_MODEL``.
|
||||
azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor
|
||||
reads ``AZURE_OPENAI_ENDPOINT``.
|
||||
@@ -1135,8 +1135,8 @@ class OpenAIChatCompletionClient( # type: ignore[misc]
|
||||
|
||||
Keyword Args:
|
||||
model: Model identifier to use for the request. When not provided, the constructor
|
||||
reads ``OPENAI_CHAT_MODEL`` and then ``OPENAI_MODEL`` for OpenAI routing,
|
||||
or ``AZURE_OPENAI_CHAT_MODEL`` and then
|
||||
reads ``OPENAI_CHAT_COMPLETION_MODEL`` and then ``OPENAI_MODEL`` for OpenAI routing,
|
||||
or ``AZURE_OPENAI_CHAT_COMPLETION_MODEL`` and then
|
||||
``AZURE_OPENAI_MODEL`` for Azure routing.
|
||||
api_key: API key override. For OpenAI routing this maps to ``OPENAI_API_KEY``.
|
||||
For Azure routing this can be used instead of ``AZURE_OPENAI_API_KEY`` for key
|
||||
@@ -1173,10 +1173,10 @@ class OpenAIChatCompletionClient( # type: ignore[misc]
|
||||
2. Explicit OpenAI API key or ``OPENAI_API_KEY``
|
||||
3. Azure environment fallback
|
||||
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_CHAT_MODEL``,
|
||||
OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_CHAT_COMPLETION_MODEL``,
|
||||
``OPENAI_MODEL``, ``OPENAI_ORG_ID``, and ``OPENAI_BASE_URL``. Azure routing
|
||||
reads ``AZURE_OPENAI_ENDPOINT``, ``AZURE_OPENAI_BASE_URL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_MODEL``,
|
||||
``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_COMPLETION_MODEL``,
|
||||
``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -67,10 +67,10 @@ class OpenAISettings(TypedDict, total=False):
|
||||
Can be set via environment variable OPENAI_MODEL.
|
||||
embedding_model: The OpenAI embedding model to use, for example, text-embedding-3-small.
|
||||
Can be set via environment variable OPENAI_EMBEDDING_MODEL.
|
||||
chat_model: The OpenAI chat-completions model to prefer before OPENAI_MODEL.
|
||||
chat_model: The OpenAIChatClient model to prefer before OPENAI_MODEL.
|
||||
Can be set via environment variable OPENAI_CHAT_MODEL.
|
||||
responses_model: The OpenAI responses model to prefer before OPENAI_MODEL.
|
||||
Can be set via environment variable OPENAI_RESPONSES_MODEL.
|
||||
chat_completion_model: The OpenAIChatCompletionClient model to prefer before OPENAI_MODEL.
|
||||
Can be set via environment variable OPENAI_CHAT_COMPLETION_MODEL.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
@@ -95,7 +95,7 @@ class OpenAISettings(TypedDict, total=False):
|
||||
model: str | None
|
||||
embedding_model: str | None
|
||||
chat_model: str | None
|
||||
responses_model: str | None
|
||||
chat_completion_model: str | None
|
||||
|
||||
|
||||
class AzureOpenAISettings(TypedDict, total=False):
|
||||
@@ -107,24 +107,24 @@ class AzureOpenAISettings(TypedDict, total=False):
|
||||
model: str | None
|
||||
embedding_model: str | None
|
||||
chat_model: str | None
|
||||
responses_model: str | None
|
||||
chat_completion_model: str | None
|
||||
api_version: str | None
|
||||
|
||||
|
||||
OpenAIModelSettingName = Literal["model", "embedding_model", "chat_model", "responses_model"]
|
||||
OpenAIModelSettingName = Literal["model", "embedding_model", "chat_model", "chat_completion_model"]
|
||||
|
||||
OPENAI_MODEL_ENV_VARS: dict[OpenAIModelSettingName, str] = {
|
||||
"model": "OPENAI_MODEL",
|
||||
"embedding_model": "OPENAI_EMBEDDING_MODEL",
|
||||
"chat_model": "OPENAI_CHAT_MODEL",
|
||||
"responses_model": "OPENAI_RESPONSES_MODEL",
|
||||
"chat_completion_model": "OPENAI_CHAT_COMPLETION_MODEL",
|
||||
}
|
||||
|
||||
AZURE_MODEL_ENV_VARS: dict[OpenAIModelSettingName, str] = {
|
||||
"model": "AZURE_OPENAI_MODEL",
|
||||
"embedding_model": "AZURE_OPENAI_EMBEDDING_MODEL",
|
||||
"chat_model": "AZURE_OPENAI_CHAT_MODEL",
|
||||
"responses_model": "AZURE_OPENAI_RESPONSES_MODEL",
|
||||
"chat_completion_model": "AZURE_OPENAI_CHAT_COMPLETION_MODEL",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,15 +43,15 @@ def openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): #
|
||||
"OPENAI_ORG_ID",
|
||||
"OPENAI_MODEL",
|
||||
"OPENAI_EMBEDDING_MODEL",
|
||||
"OPENAI_CHAT_COMPLETION_MODEL",
|
||||
"OPENAI_CHAT_MODEL",
|
||||
"OPENAI_RESPONSES_MODEL",
|
||||
"OPENAI_API_VERSION",
|
||||
"OPENAI_BASE_URL",
|
||||
"AZURE_OPENAI_ENDPOINT",
|
||||
"AZURE_OPENAI_BASE_URL",
|
||||
"AZURE_OPENAI_API_KEY",
|
||||
"AZURE_OPENAI_CHAT_COMPLETION_MODEL",
|
||||
"AZURE_OPENAI_CHAT_MODEL",
|
||||
"AZURE_OPENAI_RESPONSES_MODEL",
|
||||
"AZURE_OPENAI_EMBEDDING_MODEL",
|
||||
"AZURE_OPENAI_MODEL",
|
||||
"AZURE_OPENAI_API_VERSION",
|
||||
@@ -92,15 +92,15 @@ def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dic
|
||||
"OPENAI_ORG_ID",
|
||||
"OPENAI_MODEL",
|
||||
"OPENAI_EMBEDDING_MODEL",
|
||||
"OPENAI_CHAT_COMPLETION_MODEL",
|
||||
"OPENAI_CHAT_MODEL",
|
||||
"OPENAI_RESPONSES_MODEL",
|
||||
"OPENAI_API_VERSION",
|
||||
"OPENAI_BASE_URL",
|
||||
"AZURE_OPENAI_ENDPOINT",
|
||||
"AZURE_OPENAI_BASE_URL",
|
||||
"AZURE_OPENAI_API_KEY",
|
||||
"AZURE_OPENAI_CHAT_COMPLETION_MODEL",
|
||||
"AZURE_OPENAI_CHAT_MODEL",
|
||||
"AZURE_OPENAI_RESPONSES_MODEL",
|
||||
"AZURE_OPENAI_EMBEDDING_MODEL",
|
||||
"AZURE_OPENAI_MODEL",
|
||||
"AZURE_OPENAI_API_VERSION",
|
||||
@@ -109,8 +109,8 @@ def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dic
|
||||
|
||||
env_vars = {
|
||||
"AZURE_OPENAI_ENDPOINT": "https://test-endpoint.openai.azure.com",
|
||||
"AZURE_OPENAI_CHAT_MODEL": "test_chat_deployment",
|
||||
"AZURE_OPENAI_RESPONSES_MODEL": "test_responses_deployment",
|
||||
"AZURE_OPENAI_CHAT_COMPLETION_MODEL": "test_chat_deployment",
|
||||
"AZURE_OPENAI_CHAT_MODEL": "test_responses_deployment",
|
||||
"AZURE_OPENAI_EMBEDDING_MODEL": "test_embedding_deployment",
|
||||
"AZURE_OPENAI_MODEL": "test_deployment",
|
||||
"AZURE_OPENAI_API_KEY": "test_api_key",
|
||||
|
||||
@@ -150,12 +150,12 @@ def test_openai_chat_client_tool_methods_return_dict() -> None:
|
||||
assert web_tool.get("type") == "web_search"
|
||||
|
||||
|
||||
def test_init_prefers_openai_responses_model(monkeypatch, openai_unit_test_env: dict[str, str]) -> None:
|
||||
monkeypatch.setenv("OPENAI_RESPONSES_MODEL", "test_responses_model")
|
||||
def test_init_prefers_openai_chat_model(monkeypatch, openai_unit_test_env: dict[str, str]) -> None:
|
||||
monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_chat_model")
|
||||
|
||||
openai_responses_client = OpenAIChatClient()
|
||||
|
||||
assert openai_responses_client.model == "test_responses_model"
|
||||
assert openai_responses_client.model == "test_chat_model"
|
||||
|
||||
|
||||
def test_init_validation_fail() -> None:
|
||||
|
||||
@@ -23,7 +23,7 @@ pytestmark = pytest.mark.azure
|
||||
|
||||
skip_if_azure_openai_integration_tests_disabled = pytest.mark.skipif(
|
||||
os.getenv("AZURE_OPENAI_ENDPOINT", "") in ("", "https://test-endpoint.openai.azure.com")
|
||||
or (os.getenv("AZURE_OPENAI_RESPONSES_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""),
|
||||
or (os.getenv("AZURE_OPENAI_CHAT_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""),
|
||||
reason="No real Azure OpenAI endpoint or responses deployment provided; skipping integration tests.",
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ def _with_azure_openai_debug() -> Any:
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
model = os.getenv("AZURE_OPENAI_RESPONSES_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "<unset>")
|
||||
model = os.getenv("AZURE_OPENAI_CHAT_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "<unset>")
|
||||
api_version = os.getenv("AZURE_OPENAI_API_VERSION") or "preview"
|
||||
endpoint = os.getenv("AZURE_OPENAI_ENDPOINT", "<unset>")
|
||||
debug_message = f"Azure OpenAI debug: endpoint={endpoint}, model={model}, api_version={api_version}"
|
||||
@@ -96,7 +96,7 @@ async def get_weather(location: str) -> str:
|
||||
def test_init_with_azure_endpoint(azure_openai_unit_test_env: dict[str, str]) -> None:
|
||||
client = OpenAIChatClient(credential=AzureCliCredential())
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert isinstance(client, SupportsChatGetResponse)
|
||||
assert isinstance(client.client, AsyncAzureOpenAI)
|
||||
assert client.OTEL_PROVIDER_NAME == "azure.ai.openai"
|
||||
@@ -106,7 +106,7 @@ def test_init_with_azure_endpoint(azure_openai_unit_test_env: dict[str, str]) ->
|
||||
def test_init_auto_detects_azure_env(azure_openai_unit_test_env: dict[str, str]) -> None:
|
||||
client = OpenAIChatClient()
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert isinstance(client.client, AsyncAzureOpenAI)
|
||||
assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"]
|
||||
|
||||
@@ -141,7 +141,7 @@ def test_explicit_credential_wins_over_openai_api_key(monkeypatch, azure_openai_
|
||||
|
||||
client = OpenAIChatClient(credential=lambda: "token")
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert isinstance(client.client, AsyncAzureOpenAI)
|
||||
assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"]
|
||||
|
||||
@@ -149,7 +149,7 @@ def test_explicit_credential_wins_over_openai_api_key(monkeypatch, azure_openai_
|
||||
def test_init_falls_back_to_generic_azure_deployment_env(
|
||||
monkeypatch, azure_openai_unit_test_env: dict[str, str]
|
||||
) -> None:
|
||||
monkeypatch.delenv("AZURE_OPENAI_RESPONSES_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False)
|
||||
|
||||
client = OpenAIChatClient()
|
||||
|
||||
@@ -160,9 +160,9 @@ def test_init_falls_back_to_generic_azure_deployment_env(
|
||||
def test_init_does_not_fall_back_to_openai_responses_model_for_azure_env(
|
||||
monkeypatch, azure_openai_unit_test_env: dict[str, str]
|
||||
) -> None:
|
||||
monkeypatch.delenv("AZURE_OPENAI_RESPONSES_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False)
|
||||
monkeypatch.setenv("OPENAI_RESPONSES_MODEL", "test_responses_model")
|
||||
monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_responses_model")
|
||||
|
||||
with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"):
|
||||
OpenAIChatClient()
|
||||
@@ -171,9 +171,9 @@ def test_init_does_not_fall_back_to_openai_responses_model_for_azure_env(
|
||||
def test_init_does_not_fall_back_to_openai_model_for_azure_env(
|
||||
monkeypatch, azure_openai_unit_test_env: dict[str, str]
|
||||
) -> None:
|
||||
monkeypatch.delenv("AZURE_OPENAI_RESPONSES_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False)
|
||||
monkeypatch.delenv("OPENAI_RESPONSES_MODEL", raising=False)
|
||||
monkeypatch.delenv("OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.setenv("OPENAI_MODEL", "gpt-5")
|
||||
|
||||
with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"):
|
||||
@@ -203,7 +203,7 @@ def test_init_with_credential_wraps_async_token_credential(
|
||||
def test_init_uses_default_azure_api_version(azure_openai_unit_test_env: dict[str, str]) -> None:
|
||||
client = OpenAIChatClient(credential=AzureCliCredential())
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert client.api_version is not None
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ def test_supports_web_search_only() -> None:
|
||||
|
||||
|
||||
def test_init_prefers_openai_chat_model(monkeypatch, openai_unit_test_env: dict[str, str]) -> None:
|
||||
monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_chat_model")
|
||||
monkeypatch.setenv("OPENAI_CHAT_COMPLETION_MODEL", "test_chat_model")
|
||||
|
||||
open_ai_chat_completion = OpenAIChatCompletionClient()
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ pytestmark = pytest.mark.azure
|
||||
|
||||
skip_if_azure_openai_integration_tests_disabled = pytest.mark.skipif(
|
||||
os.getenv("AZURE_OPENAI_ENDPOINT", "") in ("", "https://test-endpoint.openai.azure.com")
|
||||
or (os.getenv("AZURE_OPENAI_CHAT_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""),
|
||||
or (os.getenv("AZURE_OPENAI_CHAT_COMPLETION_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""),
|
||||
reason="No real Azure OpenAI endpoint or chat deployment provided; skipping integration tests.",
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@ def _with_azure_openai_debug() -> Any:
|
||||
try:
|
||||
return await func(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
model = os.getenv("AZURE_OPENAI_CHAT_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "<unset>")
|
||||
model = os.getenv("AZURE_OPENAI_CHAT_COMPLETION_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "<unset>")
|
||||
api_version = os.getenv("AZURE_OPENAI_API_VERSION", "<unset>")
|
||||
endpoint = os.getenv("AZURE_OPENAI_ENDPOINT", "<unset>")
|
||||
debug_message = f"Azure OpenAI debug: endpoint={endpoint}, model={model}, api_version={api_version}"
|
||||
@@ -78,7 +78,7 @@ async def get_weather(location: str) -> str:
|
||||
def test_init_with_azure_endpoint(azure_openai_unit_test_env: dict[str, str]) -> None:
|
||||
client = OpenAIChatCompletionClient(azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"))
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_COMPLETION_MODEL"]
|
||||
assert isinstance(client, SupportsChatGetResponse)
|
||||
assert isinstance(client.client, AsyncAzureOpenAI)
|
||||
assert client.OTEL_PROVIDER_NAME == "azure.ai.openai"
|
||||
@@ -89,7 +89,7 @@ def test_init_with_azure_endpoint(azure_openai_unit_test_env: dict[str, str]) ->
|
||||
def test_init_auto_detects_azure_env(azure_openai_unit_test_env: dict[str, str]) -> None:
|
||||
client = OpenAIChatCompletionClient()
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_COMPLETION_MODEL"]
|
||||
assert isinstance(client.client, AsyncAzureOpenAI)
|
||||
assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"]
|
||||
|
||||
@@ -111,7 +111,7 @@ def test_explicit_credential_wins_over_openai_api_key(monkeypatch, azure_openai_
|
||||
|
||||
client = OpenAIChatCompletionClient(credential=lambda: "token")
|
||||
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_MODEL"]
|
||||
assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_CHAT_COMPLETION_MODEL"]
|
||||
assert isinstance(client.client, AsyncAzureOpenAI)
|
||||
assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"]
|
||||
|
||||
@@ -119,7 +119,7 @@ def test_explicit_credential_wins_over_openai_api_key(monkeypatch, azure_openai_
|
||||
def test_init_falls_back_to_generic_azure_deployment_env(
|
||||
monkeypatch, azure_openai_unit_test_env: dict[str, str]
|
||||
) -> None:
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_COMPLETION_MODEL", raising=False)
|
||||
|
||||
client = OpenAIChatCompletionClient()
|
||||
|
||||
@@ -130,9 +130,9 @@ def test_init_falls_back_to_generic_azure_deployment_env(
|
||||
def test_init_does_not_fall_back_to_openai_chat_model_for_azure_env(
|
||||
monkeypatch, azure_openai_unit_test_env: dict[str, str]
|
||||
) -> None:
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_COMPLETION_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False)
|
||||
monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_chat_model")
|
||||
monkeypatch.setenv("OPENAI_CHAT_COMPLETION_MODEL", "test_chat_model")
|
||||
|
||||
with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"):
|
||||
OpenAIChatCompletionClient()
|
||||
@@ -141,9 +141,9 @@ def test_init_does_not_fall_back_to_openai_chat_model_for_azure_env(
|
||||
def test_init_does_not_fall_back_to_openai_model_for_azure_env(
|
||||
monkeypatch, azure_openai_unit_test_env: dict[str, str]
|
||||
) -> None:
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_CHAT_COMPLETION_MODEL", raising=False)
|
||||
monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False)
|
||||
monkeypatch.delenv("OPENAI_CHAT_MODEL", raising=False)
|
||||
monkeypatch.delenv("OPENAI_CHAT_COMPLETION_MODEL", raising=False)
|
||||
monkeypatch.setenv("OPENAI_MODEL", "gpt-5")
|
||||
|
||||
with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"):
|
||||
|
||||
@@ -70,7 +70,6 @@ agent-framework-ag-ui = { workspace = true }
|
||||
agent-framework-azure-ai-search = { workspace = true }
|
||||
agent-framework-azure-cosmos = { workspace = true }
|
||||
agent-framework-anthropic = { workspace = true }
|
||||
agent-framework-azure-ai = { workspace = true }
|
||||
agent-framework-azurefunctions = { workspace = true }
|
||||
agent-framework-bedrock = { workspace = true }
|
||||
agent-framework-chatkit = { workspace = true }
|
||||
@@ -187,7 +186,6 @@ executionEnvironments = [
|
||||
{ root = "packages/ag-ui/tests", reportPrivateUsage = "none" },
|
||||
{ root = "packages/anthropic/tests", reportPrivateUsage = "none" },
|
||||
{ root = "packages/azure-ai-search/tests", reportPrivateUsage = "none" },
|
||||
{ root = "packages/azure-ai/tests", reportPrivateUsage = "none" },
|
||||
{ root = "packages/azure-cosmos/tests", reportPrivateUsage = "none" },
|
||||
{ root = "packages/azurefunctions/tests", reportPrivateUsage = "none" },
|
||||
{ root = "packages/bedrock/tests", reportPrivateUsage = "none" },
|
||||
|
||||
@@ -61,8 +61,8 @@ Depending on the selected client, set the appropriate environment variables:
|
||||
|
||||
**For OpenAI clients:**
|
||||
- `OPENAI_API_KEY`: Your OpenAI API key
|
||||
- `OPENAI_CHAT_MODEL`: The OpenAI model for `openai_chat_completion`
|
||||
- `OPENAI_RESPONSES_MODEL`: The OpenAI model for `openai_responses`
|
||||
- `OPENAI_CHAT_COMPLETION_MODEL`: The OpenAI model for `openai_chat_completion`
|
||||
- `OPENAI_CHAT_MODEL`: The OpenAI model for `openai_responses`
|
||||
|
||||
**For Anthropic client (`anthropic`):**
|
||||
- `ANTHROPIC_API_KEY`: Your Anthropic API key
|
||||
|
||||
@@ -8,6 +8,7 @@ These samples demonstrate different approaches to managing conversation history
|
||||
|------|-------------|
|
||||
| [`suspend_resume_session.py`](suspend_resume_session.py) | Suspend and resume conversation sessions, comparing service-managed sessions (Azure AI Foundry) with in-memory sessions (OpenAI). |
|
||||
| [`custom_history_provider.py`](custom_history_provider.py) | Implement a custom history provider by extending `BaseHistoryProvider`, enabling conversation persistence in your preferred storage backend. |
|
||||
| [`cosmos_history_provider.py`](cosmos_history_provider.py) | Use Azure Cosmos DB as a history provider for durable conversation storage with `CosmosHistoryProvider`. |
|
||||
| [`redis_history_provider.py`](redis_history_provider.py) | Use Redis as a history provider for persistent conversation history storage across sessions. |
|
||||
|
||||
## Prerequisites
|
||||
@@ -21,6 +22,14 @@ These samples demonstrate different approaches to managing conversation history
|
||||
**For `custom_history_provider.py`:**
|
||||
- `OPENAI_API_KEY`: Your OpenAI API key
|
||||
|
||||
**For `cosmos_history_provider.py`:**
|
||||
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
|
||||
- `FOUNDRY_MODEL`: The Foundry model deployment name
|
||||
- `AZURE_COSMOS_ENDPOINT`: Your Azure Cosmos DB account endpoint
|
||||
- `AZURE_COSMOS_DATABASE_NAME`: The database that stores conversation history
|
||||
- `AZURE_COSMOS_CONTAINER_NAME`: The container that stores conversation history
|
||||
- Either `AZURE_COSMOS_KEY` or Azure CLI authentication (`az login`)
|
||||
|
||||
**For `redis_history_provider.py`:**
|
||||
- `OPENAI_API_KEY`: Your OpenAI API key
|
||||
- A running Redis server — default URL is `redis://localhost:6379`
|
||||
|
||||
+33
-35
@@ -1,20 +1,19 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
# ruff: noqa: T201
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.azure import CosmosHistoryProvider
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from agent_framework_azure_cosmos import CosmosHistoryProvider
|
||||
|
||||
# Load environment variables from .env file.
|
||||
load_dotenv()
|
||||
|
||||
"""
|
||||
This sample demonstrates CosmosHistoryProvider as an agent context provider.
|
||||
This sample demonstrates CosmosHistoryProvider as an agent history provider.
|
||||
|
||||
Key components:
|
||||
- FoundryChatClient configured with an Azure AI project endpoint
|
||||
@@ -54,39 +53,38 @@ async def main() -> None:
|
||||
)
|
||||
return
|
||||
|
||||
# 1. Create an Azure credential and Foundry chat client using project endpoint auth.
|
||||
async with AzureCliCredential() as credential:
|
||||
client = FoundryChatClient(
|
||||
project_endpoint=project_endpoint,
|
||||
model=model,
|
||||
credential=credential,
|
||||
)
|
||||
# 1. Create an Azure credential and a CosmosHistoryProvider for agent context
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
CosmosHistoryProvider(
|
||||
endpoint=cosmos_endpoint,
|
||||
database_name=cosmos_database_name,
|
||||
container_name=cosmos_container_name,
|
||||
credential=cosmos_key or credential,
|
||||
) as history_provider,
|
||||
# 2. Create an agent that uses Cosmos for persisted conversation history.
|
||||
Agent(
|
||||
client=FoundryChatClient(
|
||||
project_endpoint=project_endpoint,
|
||||
model=model,
|
||||
credential=credential,
|
||||
),
|
||||
name="CosmosHistoryAgent",
|
||||
instructions="You are a helpful assistant that remembers prior turns.",
|
||||
context_providers=[history_provider],
|
||||
default_options={"store": False},
|
||||
) as agent,
|
||||
):
|
||||
# 3. Create a session (session_id is used as the partition key).
|
||||
session = agent.create_session()
|
||||
|
||||
# 2. Create an agent that uses the history provider as a context provider.
|
||||
async with (
|
||||
CosmosHistoryProvider(
|
||||
endpoint=cosmos_endpoint,
|
||||
database_name=cosmos_database_name,
|
||||
container_name=cosmos_container_name,
|
||||
credential=cosmos_key or credential,
|
||||
) as history_provider,
|
||||
client.as_agent(
|
||||
name="CosmosHistoryAgent",
|
||||
instructions="You are a helpful assistant that remembers prior turns.",
|
||||
context_providers=[history_provider],
|
||||
default_options={"store": False},
|
||||
) as agent,
|
||||
):
|
||||
# 3. Create a session (session_id is used as the partition key).
|
||||
session = agent.create_session()
|
||||
# 4. Run a multi-turn conversation; history is persisted by CosmosHistoryProvider.
|
||||
response1 = await agent.run("My name is Ada and I enjoy distributed systems.", session=session)
|
||||
print(f"Assistant: {response1.text}")
|
||||
|
||||
# 4. Run a multi-turn conversation; history is persisted by CosmosHistoryProvider.
|
||||
response1 = await agent.run("My name is Ada and I enjoy distributed systems.", session=session)
|
||||
print(f"Assistant: {response1.text}")
|
||||
|
||||
response2 = await agent.run("What do you remember about me?", session=session)
|
||||
print(f"Assistant: {response2.text}")
|
||||
print(f"Container: {history_provider.container_name}")
|
||||
response2 = await agent.run("What do you remember about me?", session=session)
|
||||
print(f"Assistant: {response2.text}")
|
||||
print(f"Container: {history_provider.container_name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -8,7 +8,7 @@ FOUNDRY_MODEL=gpt-4o
|
||||
|
||||
# Azure OpenAI workflow sample
|
||||
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
|
||||
AZURE_OPENAI_RESPONSES_MODEL=gpt-4o
|
||||
AZURE_OPENAI_CHAT_MODEL=gpt-4o
|
||||
# Optional fallback env name also supported by workflow_with_agents/workflow.py:
|
||||
AZURE_OPENAI_MODEL=gpt-4o
|
||||
# Optional if you need to override the default API version:
|
||||
|
||||
@@ -94,7 +94,7 @@ workflow_name/
|
||||
| Sample | What it demonstrates | Required keys / auth |
|
||||
| ------ | -------------------- | -------------------- |
|
||||
| [**workflow_declarative/**](workflow_declarative/) | A YAML-defined workflow loaded through `WorkflowFactory`, with nested age-based branching and no model client code. | None |
|
||||
| [**workflow_with_agents/**](workflow_with_agents/) | A content review workflow that uses agents as executors and routes based on structured review output (`Writer -> Reviewer -> Editor/Publisher -> Summarizer`). | `AZURE_OPENAI_ENDPOINT`, plus `AZURE_OPENAI_RESPONSES_MODEL` or `AZURE_OPENAI_MODEL`; Azure CLI auth via `az login`; `AZURE_OPENAI_API_VERSION` is optional |
|
||||
| [**workflow_with_agents/**](workflow_with_agents/) | A content review workflow that uses agents as executors and routes based on structured review output (`Writer -> Reviewer -> Editor/Publisher -> Summarizer`). | `AZURE_OPENAI_ENDPOINT`, plus `AZURE_OPENAI_CHAT_MODEL` or `AZURE_OPENAI_MODEL`; Azure CLI auth via `az login`; `AZURE_OPENAI_API_VERSION` is optional |
|
||||
| [**workflow_spam/**](workflow_spam/) | A multi-step spam detection workflow with human-in-the-loop approval, branching for spam vs. legitimate messages, and a final reporting step. | None |
|
||||
| [**workflow_fanout/**](workflow_fanout/) | A larger fan-out/fan-in data processing workflow with parallel validation, multiple transformations, QA, aggregation, and demo failure toggles. | None |
|
||||
|
||||
@@ -130,7 +130,7 @@ export FOUNDRY_MODEL="gpt-4o"
|
||||
|
||||
# Azure OpenAI workflow_with_agents sample
|
||||
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
|
||||
export AZURE_OPENAI_RESPONSES_MODEL="gpt-4o"
|
||||
export AZURE_OPENAI_CHAT_MODEL="gpt-4o"
|
||||
export AZURE_OPENAI_MODEL="gpt-4o"
|
||||
|
||||
az login
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# This sample uses Azure CLI auth, so run `az login` before starting DevUI.
|
||||
|
||||
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
|
||||
AZURE_OPENAI_RESPONSES_MODEL=gpt-4o
|
||||
AZURE_OPENAI_CHAT_MODEL=gpt-4o
|
||||
# Optional fallback env name also supported by the client:
|
||||
# AZURE_OPENAI_MODEL=gpt-4o
|
||||
# Optional if you need to override the default API version:
|
||||
|
||||
@@ -65,7 +65,7 @@ def is_approved(message: Any) -> bool:
|
||||
|
||||
# Create Azure OpenAI Responses chat client
|
||||
client = OpenAIChatClient(
|
||||
model=os.environ.get("AZURE_OPENAI_RESPONSES_MODEL") or os.environ.get("AZURE_OPENAI_MODEL"),
|
||||
model=os.environ.get("AZURE_OPENAI_CHAT_MODEL") or os.environ.get("AZURE_OPENAI_MODEL"),
|
||||
azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
|
||||
api_version=os.environ.get("AZURE_OPENAI_API_VERSION"),
|
||||
credential=AzureCliCredential(),
|
||||
|
||||
+13
-12
@@ -1,10 +1,10 @@
|
||||
# /// script
|
||||
# requires-python = ">=3.10"
|
||||
# dependencies = [
|
||||
# "agent-framework-azure-ai",
|
||||
# "agent-framework-foundry",
|
||||
# ]
|
||||
# ///
|
||||
# Run with: uv run samples/02-agents/embeddings/azure_ai_inference_embeddings.py
|
||||
# Run with: uv run samples/02-agents/embeddings/foundry_embeddings.py
|
||||
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
@@ -12,28 +12,29 @@ import asyncio
|
||||
import pathlib
|
||||
|
||||
from agent_framework import Content
|
||||
from agent_framework.azure import AzureAIInferenceEmbeddingClient
|
||||
from agent_framework.foundry import FoundryEmbeddingClient
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
"""Azure AI Inference Image Embedding Example
|
||||
"""Microsoft Foundry Image Embedding Example
|
||||
|
||||
This sample demonstrates how to generate image embeddings using the
|
||||
Azure AI Inference embedding client with the Cohere-embed-v3-english model.
|
||||
Foundry embedding client with the Cohere-embed-v3-english model.
|
||||
Images are passed as ``Content`` objects created with ``Content.from_data()``.
|
||||
|
||||
Prerequisites:
|
||||
Deploy an embedding model in Azure AI Inference that supports image inputs, such as Cohere-embed-v3-english.
|
||||
Deploy an embedding model to a Foundry-hosted inference endpoint that supports image inputs,
|
||||
such as Cohere-embed-v3-english.
|
||||
|
||||
The details page for that model, has a target URI and a Key, which should be set in environment variables or a .env
|
||||
file as follows, the target URI should append the `/models` path:
|
||||
- AZURE_AI_INFERENCE_ENDPOINT: Your Azure AI model inference endpoint URL, for instance:
|
||||
- FOUNDRY_MODELS_ENDPOINT: Your Foundry models endpoint URL, for instance:
|
||||
https://<apim-instance>.azure-api.net/<foundry-instance>/models
|
||||
- AZURE_AI_INFERENCE_API_KEY: Your API key
|
||||
- AZURE_AI_INFERENCE_EMBEDDING_MODEL: The text embedding model name
|
||||
- FOUNDRY_MODELS_API_KEY: Your API key
|
||||
- FOUNDRY_EMBEDDING_MODEL: The text embedding model name
|
||||
(e.g. "text-embedding-3-small")
|
||||
- AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL: The image embedding model name
|
||||
- FOUNDRY_IMAGE_EMBEDDING_MODEL: The image embedding model name
|
||||
(e.g. "Cohere-embed-v3-english")
|
||||
"""
|
||||
|
||||
@@ -41,8 +42,8 @@ SAMPLE_IMAGE_PATH = pathlib.Path(__file__).parent.parent.parent / "shared" / "sa
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Generate image embeddings with Azure AI Inference."""
|
||||
async with AzureAIInferenceEmbeddingClient() as client:
|
||||
"""Generate image embeddings with Foundry."""
|
||||
async with FoundryEmbeddingClient() as client:
|
||||
# 1. Generate an image embedding.
|
||||
image_bytes = SAMPLE_IMAGE_PATH.read_bytes()
|
||||
image_content = Content.from_data(data=image_bytes, media_type="image/jpeg")
|
||||
@@ -17,7 +17,7 @@ The Model Context Protocol (MCP) is an open standard for connecting AI agents to
|
||||
## Prerequisites
|
||||
|
||||
- `OPENAI_API_KEY` environment variable
|
||||
- `OPENAI_RESPONSES_MODEL` environment variable
|
||||
- `OPENAI_CHAT_MODEL` environment variable
|
||||
|
||||
Run `mcp_api_key_auth.py` with the MCP API key as the first command-line argument.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ The new usage tracking sample uses `OpenAIChatClient`, so set the usual OpenAI r
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="your-openai-api-key"
|
||||
export OPENAI_RESPONSES_MODEL="gpt-4.1-mini"
|
||||
export OPENAI_CHAT_MODEL="gpt-4.1-mini"
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
@@ -40,8 +40,8 @@ ENABLE_SENSITIVE_DATA=true
|
||||
# OpenAI specific variables
|
||||
# ==========================
|
||||
OPENAI_API_KEY="..."
|
||||
OPENAI_RESPONSES_MODEL="gpt-4o-2024-08-06"
|
||||
OPENAI_CHAT_MODEL="gpt-4o-2024-08-06"
|
||||
OPENAI_CHAT_COMPLETION_MODEL="gpt-4o-2024-08-06"
|
||||
|
||||
# Azure AI Foundry specific variables
|
||||
# ====================================
|
||||
|
||||
@@ -115,7 +115,9 @@ Orchestration-focused samples (Sequential, Concurrent, Handoff, GroupChat, Magen
|
||||
| Sample | File | Concepts |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
|
||||
| State with Agents | [state-management/state_with_agents.py](./state-management/state_with_agents.py) | Store in state once and later reuse across agents |
|
||||
| Workflow Kwargs (Custom Context) | [state-management/workflow_kwargs.py](./state-management/workflow_kwargs.py) | Pass custom context (data, user tokens) via kwargs to `@tool` tools |
|
||||
| Workflow Kwargs - Global Context | [state-management/workflow_kwargs_global.py](./state-management/workflow_kwargs_global.py) | Pass custom context (data, user tokens) via kwargs to `@tool` tools in all agents |
|
||||
| Workflow Kwargs - Per Agent | [state-management/workflow_kwargs_per_agent.py](./state-management/workflow_kwargs_per_agent.py) | Pass custom context (data, user tokens) via kwargs to `@tool` tools in individual agents |
|
||||
|
||||
|
||||
### visualization
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# OpenAI Configuration
|
||||
OPENAI_API_KEY=
|
||||
OPENAI_CHAT_MODEL=
|
||||
OPENAI_CHAT_COMPLETION_MODEL=
|
||||
|
||||
# Agent 365 Agentic Authentication Configuration
|
||||
USE_ANONYMOUS_MODE=
|
||||
|
||||
@@ -21,7 +21,7 @@ export USE_ANONYMOUS_MODE=True # set to false if using auth
|
||||
|
||||
# OpenAI
|
||||
export OPENAI_API_KEY="..."
|
||||
export OPENAI_CHAT_MODEL="..."
|
||||
export OPENAI_CHAT_COMPLETION_MODEL="..."
|
||||
```
|
||||
|
||||
## Installing Dependencies
|
||||
|
||||
@@ -92,10 +92,10 @@ variable.
|
||||
| --- | --- | --- | --- |
|
||||
| `agent-framework-anthropic` | `AnthropicClient` | `ANTHROPIC_API_KEY` | `sk-ant-api03-...` |
|
||||
| `agent-framework-anthropic` | `AnthropicClient` | `ANTHROPIC_CHAT_MODEL` | `claude-sonnet-4-5-20250929` |
|
||||
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_ENDPOINT` | `https://my-endpoint.inference.ai.azure.com` |
|
||||
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_API_KEY` | `env-key` |
|
||||
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_EMBEDDING_MODEL` | `text-embedding-3-small` |
|
||||
| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL` | `Cohere-embed-v3-english` |
|
||||
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_MODELS_ENDPOINT` | `https://my-endpoint.inference.ai.azure.com` |
|
||||
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_MODELS_API_KEY` | `env-key` |
|
||||
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_EMBEDDING_MODEL` | `text-embedding-3-small` |
|
||||
| `agent-framework-foundry` | `FoundryEmbeddingClient` | `FOUNDRY_IMAGE_EMBEDDING_MODEL` | `Cohere-embed-v3-english` |
|
||||
| `agent-framework-azure-ai-search` | `AzureAISearchContextProvider` | `AZURE_SEARCH_ENDPOINT` | `https://my-search.search.windows.net` |
|
||||
| `agent-framework-azure-ai-search` | `AzureAISearchContextProvider` | `AZURE_SEARCH_API_KEY` | `search-key` |
|
||||
| `agent-framework-azure-ai-search` | `AzureAISearchContextProvider` | `AZURE_SEARCH_INDEX_NAME` | `hotels-index` |
|
||||
@@ -144,8 +144,8 @@ variable.
|
||||
| `agent-framework-ollama` | `OllamaChatClient` | `OLLAMA_MODEL` | `llama3.1:8b` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_API_KEY` | `sk-proj-...` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_MODEL` | `gpt-4o-mini` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient` | `OPENAI_RESPONSES_MODEL` | `gpt-4.1-mini` |
|
||||
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `OPENAI_CHAT_MODEL` | `gpt-4o` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient` | `OPENAI_CHAT_MODEL` | `gpt-4.1-mini` |
|
||||
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `OPENAI_CHAT_COMPLETION_MODEL` | `gpt-4o` |
|
||||
| `agent-framework-openai` | `OpenAIEmbeddingClient` | `OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_BASE_URL` | `https://api.openai.com/v1/` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `OPENAI_ORG_ID` | `org_123456789` |
|
||||
@@ -154,8 +154,8 @@ variable.
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_API_VERSION` | `2024-10-21` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_BASE_URL` | `https://my-resource.openai.azure.com/openai/v1/` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_MODEL` | `gpt-4o` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient` | `AZURE_OPENAI_RESPONSES_MODEL` | `gpt-4.1` |
|
||||
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `AZURE_OPENAI_CHAT_MODEL` | `gpt-4o-mini` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient` | `AZURE_OPENAI_CHAT_MODEL` | `gpt-4.1` |
|
||||
| `agent-framework-openai` | `OpenAIChatCompletionClient` | `AZURE_OPENAI_CHAT_COMPLETION_MODEL` | `gpt-4o-mini` |
|
||||
| `agent-framework-openai` | `OpenAIEmbeddingClient` | `AZURE_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-large` |
|
||||
| `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_RESOURCE_URL` | `https://cognitiveservices.azure.com/` |
|
||||
|
||||
|
||||
Generated
+4
-42
@@ -30,7 +30,6 @@ members = [
|
||||
"agent-framework-a2a",
|
||||
"agent-framework-ag-ui",
|
||||
"agent-framework-anthropic",
|
||||
"agent-framework-azure-ai",
|
||||
"agent-framework-azure-ai-search",
|
||||
"agent-framework-azure-cosmos",
|
||||
"agent-framework-azurefunctions",
|
||||
@@ -203,31 +202,6 @@ requires-dist = [
|
||||
{ name = "anthropic", specifier = ">=0.80.0,<0.80.1" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agent-framework-azure-ai"
|
||||
version = "1.0.0rc6"
|
||||
source = { editable = "packages/azure-ai" }
|
||||
dependencies = [
|
||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-openai", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "aiohttp", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "azure-ai-agents", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "azure-ai-inference", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "azure-ai-projects", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "azure-identity", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "agent-framework-core", editable = "packages/core" },
|
||||
{ name = "agent-framework-openai", editable = "packages/openai" },
|
||||
{ name = "aiohttp", specifier = ">=3.7.0,<4" },
|
||||
{ name = "azure-ai-agents", specifier = ">=1.2.0b5,<1.2.0b6" },
|
||||
{ name = "azure-ai-inference", specifier = ">=1.0.0b9,<1.0.0b10" },
|
||||
{ name = "azure-ai-projects", specifier = ">=2.0.0,<3.0" },
|
||||
{ name = "azure-identity", specifier = ">=1,<2" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "agent-framework-azure-ai-search"
|
||||
version = "1.0.0b260330"
|
||||
@@ -358,8 +332,8 @@ all = [
|
||||
{ name = "agent-framework-a2a", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-ag-ui", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-anthropic", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-azure-ai", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-azure-ai-search", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-azure-cosmos", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-azurefunctions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-bedrock", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-chatkit", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
@@ -386,8 +360,8 @@ requires-dist = [
|
||||
{ name = "agent-framework-a2a", marker = "extra == 'all'", editable = "packages/a2a" },
|
||||
{ name = "agent-framework-ag-ui", marker = "extra == 'all'", editable = "packages/ag-ui" },
|
||||
{ name = "agent-framework-anthropic", marker = "extra == 'all'", editable = "packages/anthropic" },
|
||||
{ name = "agent-framework-azure-ai", marker = "extra == 'all'", editable = "packages/azure-ai" },
|
||||
{ name = "agent-framework-azure-ai-search", marker = "extra == 'all'", editable = "packages/azure-ai-search" },
|
||||
{ name = "agent-framework-azure-cosmos", marker = "extra == 'all'", editable = "packages/azure-cosmos" },
|
||||
{ name = "agent-framework-azurefunctions", marker = "extra == 'all'", editable = "packages/azurefunctions" },
|
||||
{ name = "agent-framework-bedrock", marker = "extra == 'all'", editable = "packages/bedrock" },
|
||||
{ name = "agent-framework-chatkit", marker = "extra == 'all'", editable = "packages/chatkit" },
|
||||
@@ -511,6 +485,7 @@ source = { editable = "packages/foundry" }
|
||||
dependencies = [
|
||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "agent-framework-openai", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "azure-ai-inference", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "azure-ai-projects", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
|
||||
@@ -518,6 +493,7 @@ dependencies = [
|
||||
requires-dist = [
|
||||
{ name = "agent-framework-core", editable = "packages/core" },
|
||||
{ name = "agent-framework-openai", editable = "packages/openai" },
|
||||
{ name = "azure-ai-inference", specifier = ">=1.0.0b9,<1.0.0b10" },
|
||||
{ name = "azure-ai-projects", specifier = ">=2.0.0,<3.0" },
|
||||
]
|
||||
|
||||
@@ -1020,20 +996,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure-ai-agents"
|
||||
version = "1.2.0b5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "azure-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "isodate", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ed/57/8adeed578fa8984856c67b4229e93a58e3f6024417d448d0037aafa4ee9b/azure_ai_agents-1.2.0b5.tar.gz", hash = "sha256:1a16ef3f305898aac552269f01536c34a00473dedee0bca731a21fdb739ff9d5", size = 394876, upload-time = "2025-09-30T01:55:02.328Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/6d/15070d23d7a94833a210da09d5d7ed3c24838bb84f0463895e5d159f1695/azure_ai_agents-1.2.0b5-py3-none-any.whl", hash = "sha256:257d0d24a6bf13eed4819cfa5c12fb222e5908deafb3cbfd5711d3a511cc4e88", size = 217948, upload-time = "2025-09-30T01:55:04.155Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "azure-ai-inference"
|
||||
version = "1.0.0b9"
|
||||
|
||||
Reference in New Issue
Block a user