diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml index 71f4267e41..06720cc7dd 100644 --- a/.github/workflows/python-integration-tests.yml +++ b/.github/workflows/python-integration-tests.yml @@ -95,10 +95,10 @@ jobs: environment: integration timeout-minutes: 60 env: - AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} - AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }} + AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_RESPONSES_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }} AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} defaults: run: @@ -139,7 +139,7 @@ jobs: timeout-minutes: 60 env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - ANTHROPIC_CHAT_MODEL_ID: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} + ANTHROPIC_CHAT_MODEL: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }} defaults: run: @@ -207,8 +207,8 @@ jobs: OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }} OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }} FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }} FUNCTIONS_WORKER_RUNTIME: "python" @@ -256,7 +256,7 @@ jobs: timeout-minutes: 60 env: AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }} - AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREAI__DEPLOYMENTNAME }} + AZURE_AI_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }} FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }} FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }} FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }} diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 8c8abec84a..12b602d0eb 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -192,10 +192,10 @@ jobs: runs-on: ubuntu-latest environment: integration env: - AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} - AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }} + AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_RESPONSES_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }} AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} defaults: run: @@ -255,7 +255,7 @@ jobs: environment: integration env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - ANTHROPIC_CHAT_MODEL_ID: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} + ANTHROPIC_CHAT_MODEL: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }} defaults: run: @@ -336,8 +336,8 @@ jobs: OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }} OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }} FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }} FUNCTIONS_WORKER_RUNTIME: "python" @@ -398,7 +398,7 @@ jobs: environment: integration env: AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }} - AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREAI__DEPLOYMENTNAME }} + AZURE_AI_MODEL: ${{ vars.AZUREAI__DEPLOYMENTNAME }} FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }} FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }} FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }} diff --git a/.github/workflows/python-sample-validation.yml b/.github/workflows/python-sample-validation.yml index bbb3195d1a..57746935ee 100644 --- a/.github/workflows/python-sample-validation.yml +++ b/.github/workflows/python-sample-validation.yml @@ -65,12 +65,13 @@ jobs: FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # Azure OpenAI configuration AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} - AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME || vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_RESPONSES_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME || vars.AZUREOPENAI__EMBEDDINGDEPLOYMENTNAME }} # OpenAI configuration OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} - OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }} - OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }} + OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }} + OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} # GitHub MCP GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} @@ -95,11 +96,12 @@ jobs: echo "FOUNDRY_PROJECT_ENDPOINT=$FOUNDRY_PROJECT_ENDPOINT" >> .env echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env - echo "AZURE_OPENAI_DEPLOYMENT_NAME=$AZURE_OPENAI_DEPLOYMENT_NAME" >> .env - echo "AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME=$AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME" >> .env + echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env + echo "AZURE_OPENAI_RESPONSES_MODEL=$AZURE_OPENAI_RESPONSES_MODEL" >> .env + echo "AZURE_OPENAI_EMBEDDING_MODEL=$AZURE_OPENAI_EMBEDDING_MODEL" >> .env echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env - echo "OPENAI_CHAT_MODEL_ID=$OPENAI_CHAT_MODEL_ID" >> .env - echo "OPENAI_RESPONSES_MODEL_ID=$OPENAI_RESPONSES_MODEL_ID" >> .env + echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env + echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env echo "GITHUB_PAT=$GITHUB_PAT" >> .env - name: Run sample validation @@ -120,8 +122,8 @@ jobs: env: OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} OPENAI_MODEL: ${{ vars.OPENAI__CHATMODELID }} - OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }} - OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }} + OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }} + OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} defaults: run: working-directory: python @@ -140,8 +142,8 @@ jobs: run: | echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env echo "OPENAI_MODEL=$OPENAI_MODEL" >> .env - echo "OPENAI_CHAT_MODEL_ID=$OPENAI_CHAT_MODEL_ID" >> .env - echo "OPENAI_RESPONSES_MODEL_ID=$OPENAI_RESPONSES_MODEL_ID" >> .env + echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env + echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env - name: Run sample validation run: | @@ -160,7 +162,7 @@ jobs: environment: integration env: AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} AZURE_OPENAI_API_VERSION: ${{ vars.AZURE_OPENAI_API_VERSION || '' }} defaults: run: @@ -179,7 +181,7 @@ jobs: - name: Create .env for samples run: | echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env - echo "AZURE_OPENAI_DEPLOYMENT_NAME=$AZURE_OPENAI_DEPLOYMENT_NAME" >> .env + echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env echo "AZURE_OPENAI_API_VERSION=$AZURE_OPENAI_API_VERSION" >> .env - name: Run sample validation @@ -199,7 +201,7 @@ jobs: environment: integration env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - ANTHROPIC_CHAT_MODEL_ID: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} + ANTHROPIC_CHAT_MODEL: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} defaults: run: working-directory: python @@ -217,7 +219,7 @@ jobs: - name: Create .env for samples run: | echo "ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY" >> .env - echo "ANTHROPIC_CHAT_MODEL_ID=$ANTHROPIC_CHAT_MODEL_ID" >> .env + echo "ANTHROPIC_CHAT_MODEL=$ANTHROPIC_CHAT_MODEL" >> .env - name: Run sample validation run: | @@ -265,7 +267,7 @@ jobs: runs-on: ubuntu-latest environment: integration env: - BEDROCK_CHAT_MODEL_ID: ${{ vars.BEDROCK__CHATMODELID }} + BEDROCK_CHAT_MODEL: ${{ vars.BEDROCK__CHATMODELID }} defaults: run: working-directory: python @@ -518,7 +520,7 @@ jobs: FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # Azure OpenAI configuration AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # Azure AI Search (for evaluation samples) AZURE_SEARCH_ENDPOINT: ${{ secrets.AZURE_SEARCH_ENDPOINT }} AZURE_SEARCH_API_KEY: ${{ secrets.AZURE_SEARCH_API_KEY }} @@ -560,11 +562,11 @@ jobs: FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # Azure OpenAI configuration AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # OpenAI configuration OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} - OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }} - OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }} + OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }} + OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} defaults: run: @@ -585,10 +587,10 @@ jobs: echo "FOUNDRY_PROJECT_ENDPOINT=$FOUNDRY_PROJECT_ENDPOINT" >> .env echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env - echo "AZURE_OPENAI_DEPLOYMENT_NAME=$AZURE_OPENAI_DEPLOYMENT_NAME" >> .env + echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env - echo "OPENAI_CHAT_MODEL_ID=$OPENAI_CHAT_MODEL_ID" >> .env - echo "OPENAI_RESPONSES_MODEL_ID=$OPENAI_RESPONSES_MODEL_ID" >> .env + echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env + echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env - name: Run sample validation run: | @@ -610,11 +612,11 @@ jobs: FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # Azure OpenAI configuration AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} - AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_MODEL: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME || vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} # OpenAI configuration OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} - OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }} - OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }} + OPENAI_CHAT_MODEL: ${{ vars.OPENAI__CHATMODELID }} + OPENAI_RESPONSES_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }} # Copilot Studio COPILOTSTUDIOAGENT__ENVIRONMENTID: ${{ secrets.COPILOTSTUDIOAGENT__ENVIRONMENTID }} @@ -640,10 +642,10 @@ jobs: echo "FOUNDRY_PROJECT_ENDPOINT=$FOUNDRY_PROJECT_ENDPOINT" >> .env echo "FOUNDRY_MODEL=$FOUNDRY_MODEL" >> .env echo "AZURE_OPENAI_ENDPOINT=$AZURE_OPENAI_ENDPOINT" >> .env - echo "AZURE_OPENAI_DEPLOYMENT_NAME=$AZURE_OPENAI_DEPLOYMENT_NAME" >> .env + echo "AZURE_OPENAI_MODEL=$AZURE_OPENAI_MODEL" >> .env echo "OPENAI_API_KEY=$OPENAI_API_KEY" >> .env - echo "OPENAI_CHAT_MODEL_ID=$OPENAI_CHAT_MODEL_ID" >> .env - echo "OPENAI_RESPONSES_MODEL_ID=$OPENAI_RESPONSES_MODEL_ID" >> .env + echo "OPENAI_CHAT_MODEL=$OPENAI_CHAT_MODEL" >> .env + echo "OPENAI_RESPONSES_MODEL=$OPENAI_RESPONSES_MODEL" >> .env echo "COPILOTSTUDIOAGENT__ENVIRONMENTID=$COPILOTSTUDIOAGENT__ENVIRONMENTID" >> .env echo "COPILOTSTUDIOAGENT__SCHEMANAME=$COPILOTSTUDIOAGENT__SCHEMANAME" >> .env echo "COPILOTSTUDIOAGENT__TENANTID=$COPILOTSTUDIOAGENT__TENANTID" >> .env diff --git a/python/.env.example b/python/.env.example index 4e7ba727e5..e5ae5f09d7 100644 --- a/python/.env.example +++ b/python/.env.example @@ -17,8 +17,8 @@ OPENAI_CHAT_MODEL="" OPENAI_RESPONSES_MODEL="" # Azure OpenAI AZURE_OPENAI_ENDPOINT="" -AZURE_OPENAI_CHAT_DEPLOYMENT_NAME="" -AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME="" +AZURE_OPENAI_CHAT_MODEL="" +AZURE_OPENAI_RESPONSES_MODEL="" # Mem0 MEM0_API_KEY="" # Copilot Studio diff --git a/python/CODING_STANDARD.md b/python/CODING_STANDARD.md index 22173cfb9a..3ffeb3562d 100644 --- a/python/CODING_STANDARD.md +++ b/python/CODING_STANDARD.md @@ -480,7 +480,7 @@ A more complete example with keyword arguments and code samples: ```python def create_client( - model_id: str | None = None, + model: str | None = None, *, timeout: float | None = None, env_file_path: str | None = None, @@ -489,7 +489,7 @@ def create_client( """Create a new client with the specified configuration. Args: - model_id: The model ID to use. If not provided, + model: The model ID to use. If not provided, it will be loaded from settings. Keyword Args: @@ -501,14 +501,14 @@ def create_client( A configured client instance. Raises: - ValueError: If the model_id is invalid. + ValueError: If the model is invalid. Examples: .. code-block:: python # Create a client with default settings: - client = create_client(model_id="gpt-4o") + client = create_client(model="gpt-4o") # Or load from environment: client = create_client(env_file_path=".env") diff --git a/python/README.md b/python/README.md index 1f1977358c..d9d65247ab 100644 --- a/python/README.md +++ b/python/README.md @@ -51,7 +51,7 @@ OPENAI_MODEL=... ... AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=... -AZURE_OPENAI_DEPLOYMENT_NAME=... +AZURE_OPENAI_MODEL=... ... FOUNDRY_PROJECT_ENDPOINT=... FOUNDRY_MODEL=... diff --git a/python/packages/ag-ui/agent_framework_ag_ui/_types.py b/python/packages/ag-ui/agent_framework_ag_ui/_types.py index 4c5467bd64..c8ee728df3 100644 --- a/python/packages/ag-ui/agent_framework_ag_ui/_types.py +++ b/python/packages/ag-ui/agent_framework_ag_ui/_types.py @@ -108,7 +108,7 @@ class AGUIChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], tota Keys: # Inherited from ChatOptions (forwarded to remote server): - model_id: The model identifier (forwarded as-is to server). + model: The model identifier (forwarded as-is to server). temperature: Sampling temperature. top_p: Nucleus sampling parameter. max_tokens: Maximum tokens to generate. diff --git a/python/packages/ag-ui/getting_started/README.md b/python/packages/ag-ui/getting_started/README.md index 6c414e9c14..71bd855c3a 100644 --- a/python/packages/ag-ui/getting_started/README.md +++ b/python/packages/ag-ui/getting_started/README.md @@ -191,13 +191,13 @@ from fastapi import FastAPI # Read required configuration endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") -deployment_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME") +model = os.environ.get("AZURE_OPENAI_MODEL") api_key = os.environ.get("AZURE_OPENAI_API_KEY") if not endpoint: raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required") -if not deployment_name: - raise ValueError("AZURE_OPENAI_DEPLOYMENT_NAME environment variable is required") +if not model: + raise ValueError("AZURE_OPENAI_MODEL environment variable is required") if not api_key: raise ValueError("AZURE_OPENAI_API_KEY environment variable is required") @@ -207,7 +207,7 @@ agent = Agent( instructions="You are a helpful assistant.", client=OpenAIChatCompletionClient( azure_endpoint=endpoint, - model=deployment_name, + model=model, api_key=api_key, ), ) @@ -230,7 +230,7 @@ if __name__ == "__main__": - **`Agent`**: The agent that will handle incoming requests - **FastAPI Integration**: Uses FastAPI's native async support for streaming responses - **Instructions**: The agent is created with default instructions, which can be overridden by client messages -- **Configuration**: `OpenAIChatCompletionClient` can read from environment variables (`AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_DEPLOYMENT_NAME`, `AZURE_OPENAI_API_KEY`) or accept parameters directly +- **Configuration**: `OpenAIChatCompletionClient` can read from environment variables (`AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_MODEL`, `AZURE_OPENAI_API_KEY`) or accept parameters directly **Alternative (simpler)**: Use environment variables only: @@ -249,7 +249,7 @@ Set the required environment variables: ```bash export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/" -export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini" +export AZURE_OPENAI_MODEL="gpt-4o-mini" # Optional: Set API key if not using DefaultAzureCredential # export AZURE_OPENAI_API_KEY="your-api-key" ``` diff --git a/python/packages/ag-ui/getting_started/server.py b/python/packages/ag-ui/getting_started/server.py index dd1f4b7326..4dfe0b3614 100644 --- a/python/packages/ag-ui/getting_started/server.py +++ b/python/packages/ag-ui/getting_started/server.py @@ -26,12 +26,12 @@ logger = logging.getLogger(__name__) # Read required configuration endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") -deployment_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME") +model = os.environ.get("AZURE_OPENAI_MODEL") if not endpoint: raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required") -if not deployment_name: - raise ValueError("AZURE_OPENAI_DEPLOYMENT_NAME environment variable is required") +if not model: + raise ValueError("AZURE_OPENAI_MODEL environment variable is required") # ============================================================================ @@ -121,7 +121,7 @@ agent = Agent( instructions="You are a helpful assistant. Use get_weather for weather and get_time_zone for time zones.", client=OpenAIChatCompletionClient( azure_endpoint=endpoint, - model=deployment_name, + model=model, ), tools=[get_time_zone], # ONLY server-side tools ) diff --git a/python/packages/anthropic/AGENTS.md b/python/packages/anthropic/AGENTS.md index 748f9a26f0..ce70e9d9a0 100644 --- a/python/packages/anthropic/AGENTS.md +++ b/python/packages/anthropic/AGENTS.md @@ -5,6 +5,9 @@ Integration with Anthropic's Claude API. ## Main Classes - **`AnthropicClient`** - Chat client for Anthropic Claude models +- **`AnthropicFoundryClient`** - Anthropic chat client for Azure AI Foundry's Anthropic-compatible endpoint +- **`AnthropicBedrockClient`** - Anthropic chat client for Amazon Bedrock +- **`AnthropicVertexClient`** - Anthropic chat client for Google Vertex AI - **`AnthropicChatOptions`** - Options TypedDict for Anthropic-specific parameters ## Usage @@ -12,7 +15,7 @@ Integration with Anthropic's Claude API. ```python from agent_framework.anthropic import AnthropicClient -client = AnthropicClient(model_id="claude-sonnet-4-20250514") +client = AnthropicClient(model="claude-sonnet-4-20250514") response = await client.get_response("Hello") ``` diff --git a/python/packages/anthropic/README.md b/python/packages/anthropic/README.md index 2507837d2c..f27b53acdc 100644 --- a/python/packages/anthropic/README.md +++ b/python/packages/anthropic/README.md @@ -10,6 +10,12 @@ pip install agent-framework-anthropic --pre The Anthropic integration enables communication with the Anthropic API, allowing your Agent Framework applications to leverage Anthropic's capabilities. +The package also includes Anthropic-hosted transport wrappers for: + +- Azure AI Foundry via `AnthropicFoundryClient` +- Amazon Bedrock via `AnthropicBedrockClient` +- Google Vertex AI via `AnthropicVertexClient` + ### Basic Usage Example See the [Anthropic agent examples](../../samples/02-agents/providers/anthropic/) which demonstrate: diff --git a/python/packages/anthropic/agent_framework_anthropic/__init__.py b/python/packages/anthropic/agent_framework_anthropic/__init__.py index ad0cff9648..0f4c1c9148 100644 --- a/python/packages/anthropic/agent_framework_anthropic/__init__.py +++ b/python/packages/anthropic/agent_framework_anthropic/__init__.py @@ -2,7 +2,10 @@ import importlib.metadata +from ._bedrock_client import AnthropicBedrockClient, RawAnthropicBedrockClient from ._chat_client import AnthropicChatOptions, AnthropicClient, RawAnthropicClient +from ._foundry_client import AnthropicFoundryClient, RawAnthropicFoundryClient +from ._vertex_client import AnthropicVertexClient, RawAnthropicVertexClient try: __version__ = importlib.metadata.version(__name__) @@ -10,8 +13,14 @@ except importlib.metadata.PackageNotFoundError: __version__ = "0.0.0" # Fallback for development mode __all__ = [ + "AnthropicBedrockClient", "AnthropicChatOptions", "AnthropicClient", + "AnthropicFoundryClient", + "AnthropicVertexClient", + "RawAnthropicBedrockClient", "RawAnthropicClient", + "RawAnthropicFoundryClient", + "RawAnthropicVertexClient", "__version__", ] diff --git a/python/packages/anthropic/agent_framework_anthropic/_bedrock_client.py b/python/packages/anthropic/agent_framework_anthropic/_bedrock_client.py new file mode 100644 index 0000000000..8b7b6bd71b --- /dev/null +++ b/python/packages/anthropic/agent_framework_anthropic/_bedrock_client.py @@ -0,0 +1,168 @@ +# Copyright (c) Microsoft. All rights reserved. + +from __future__ import annotations + +from collections.abc import Sequence +from typing import Any, ClassVar, Generic, TypedDict + +from agent_framework import ( + AGENT_FRAMEWORK_USER_AGENT, + ChatAndFunctionMiddlewareTypes, + ChatMiddlewareLayer, + FunctionInvocationConfiguration, + FunctionInvocationLayer, +) +from agent_framework._settings import SecretString, load_settings +from agent_framework.observability import ChatTelemetryLayer +from anthropic import AsyncAnthropicBedrock + +from ._chat_client import AnthropicOptionsT, RawAnthropicClient + + +class AnthropicBedrockSettings(TypedDict, total=False): + """Resolved settings for Anthropic Bedrock wrappers.""" + + aws_access_key_id: SecretString | None + aws_secret_access_key: SecretString | None + aws_region: str | None + aws_profile: str | None + aws_session_token: SecretString | None + anthropic_bedrock_base_url: str | None + anthropic_chat_model: str | None + + +class RawAnthropicBedrockClient(RawAnthropicClient[AnthropicOptionsT], Generic[AnthropicOptionsT]): + """Raw Anthropic Bedrock chat client without middleware, telemetry, or function invocation support.""" + + OTEL_PROVIDER_NAME: ClassVar[str] = "aws.bedrock" # type: ignore[reportIncompatibleVariableOverride, misc] + + def __init__( + self, + *, + model: str | None = None, + aws_secret_key: str | None = None, + aws_access_key: str | None = None, + aws_region: str | None = None, + aws_profile: str | None = None, + aws_session_token: str | None = None, + base_url: str | None = None, + anthropic_client: AsyncAnthropicBedrock | None = None, + additional_beta_flags: list[str] | None = None, + additional_properties: dict[str, Any] | None = None, + env_file_path: str | None = None, + env_file_encoding: str | None = None, + ) -> None: + """Initialize a raw Anthropic Bedrock client. + + Keyword Args: + model: The Anthropic model to use. + aws_secret_key: AWS secret access key. + aws_access_key: AWS access key ID. + aws_region: AWS region. + aws_profile: AWS profile name. + aws_session_token: AWS session token. + base_url: Optional custom Anthropic Bedrock base URL. + anthropic_client: Existing AsyncAnthropicBedrock client to reuse. + additional_beta_flags: Additional beta flags to enable on the client. + additional_properties: Additional properties stored on the client instance. + env_file_path: Path to environment file for loading settings. + env_file_encoding: Encoding of the environment file. + """ + settings = load_settings( + AnthropicBedrockSettings, + env_prefix="", + aws_access_key_id=aws_access_key, + aws_secret_access_key=aws_secret_key, + aws_region=aws_region, + aws_profile=aws_profile, + aws_session_token=aws_session_token, + anthropic_bedrock_base_url=base_url, + anthropic_chat_model=model, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) + model_setting = settings.get("anthropic_chat_model") + access_key_secret = settings.get("aws_access_key_id") + secret_key_secret = settings.get("aws_secret_access_key") + session_token_secret = settings.get("aws_session_token") + + if anthropic_client is None: + anthropic_client = AsyncAnthropicBedrock( + aws_secret_key=secret_key_secret.get_secret_value() if secret_key_secret is not None else None, + aws_access_key=access_key_secret.get_secret_value() if access_key_secret is not None else None, + aws_region=settings.get("aws_region"), + aws_profile=settings.get("aws_profile"), + aws_session_token=session_token_secret.get_secret_value() if session_token_secret is not None else None, + base_url=settings.get("anthropic_bedrock_base_url"), + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + + super().__init__( + model=model_setting, + anthropic_client=anthropic_client, + additional_beta_flags=additional_beta_flags, + additional_properties=additional_properties, + ) + + +class AnthropicBedrockClient( # type: ignore[misc] + FunctionInvocationLayer[AnthropicOptionsT], + ChatMiddlewareLayer[AnthropicOptionsT], + ChatTelemetryLayer[AnthropicOptionsT], + RawAnthropicBedrockClient[AnthropicOptionsT], + Generic[AnthropicOptionsT], +): + """Anthropic Bedrock chat client with middleware, telemetry, and function invocation support.""" + + def __init__( + self, + *, + model: str | None = None, + aws_secret_key: str | None = None, + aws_access_key: str | None = None, + aws_region: str | None = None, + aws_profile: str | None = None, + aws_session_token: str | None = None, + base_url: str | None = None, + anthropic_client: AsyncAnthropicBedrock | None = None, + additional_beta_flags: list[str] | None = None, + additional_properties: dict[str, Any] | None = None, + middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None, + function_invocation_configuration: FunctionInvocationConfiguration | None = None, + env_file_path: str | None = None, + env_file_encoding: str | None = None, + ) -> None: + """Initialize an Anthropic Bedrock client. + + Keyword Args: + model: The Anthropic model to use. + aws_secret_key: AWS secret access key. + aws_access_key: AWS access key ID. + aws_region: AWS region. + aws_profile: AWS profile name. + aws_session_token: AWS session token. + base_url: Optional custom Anthropic Bedrock base URL. + anthropic_client: Existing AsyncAnthropicBedrock client to reuse. + additional_beta_flags: Additional beta flags to enable on the client. + additional_properties: Additional properties stored on the client instance. + middleware: Optional middleware to apply to the client. + function_invocation_configuration: Optional function invocation configuration override. + env_file_path: Path to environment file for loading settings. + env_file_encoding: Encoding of the environment file. + """ + super().__init__( + model=model, + aws_secret_key=aws_secret_key, + aws_access_key=aws_access_key, + aws_region=aws_region, + aws_profile=aws_profile, + aws_session_token=aws_session_token, + base_url=base_url, + anthropic_client=anthropic_client, + additional_beta_flags=additional_beta_flags, + additional_properties=additional_properties, + middleware=middleware, + function_invocation_configuration=function_invocation_configuration, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) diff --git a/python/packages/anthropic/agent_framework_anthropic/_chat_client.py b/python/packages/anthropic/agent_framework_anthropic/_chat_client.py index b3b61a4640..ebe03411a3 100644 --- a/python/packages/anthropic/agent_framework_anthropic/_chat_client.py +++ b/python/packages/anthropic/agent_framework_anthropic/_chat_client.py @@ -31,7 +31,7 @@ from agent_framework._settings import SecretString, load_settings from agent_framework._tools import SHELL_TOOL_KIND_VALUE from agent_framework._types import _get_data_bytes_as_str # type: ignore from agent_framework.observability import ChatTelemetryLayer -from anthropic import AsyncAnthropic +from anthropic import AsyncAnthropic, AsyncAnthropicBedrock, AsyncAnthropicFoundry, AsyncAnthropicVertex from anthropic.types.beta import ( BetaContentBlock, BetaMessage, @@ -79,6 +79,7 @@ BETA_FLAGS: Final[list[str]] = ["mcp-client-2025-04-04", "code-execution-2025-08 STRUCTURED_OUTPUTS_BETA_FLAG: Final[str] = "structured-outputs-2025-11-13" ResponseModelT = TypeVar("ResponseModelT", bound=BaseModel | None, default=None) +AnthropicAsyncClient = AsyncAnthropic | AsyncAnthropicBedrock | AsyncAnthropicFoundry | AsyncAnthropicVertex # region Anthropic Chat Options TypedDict @@ -113,8 +114,6 @@ class AnthropicChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], a default of 1024 will be used. Keys: - model_id: The model to use for the request, - translates to ``model`` in Anthropic API. temperature: Sampling temperature between 0 and 1. top_p: Nucleus sampling parameter. max_tokens: Maximum number of tokens to generate (REQUIRED). @@ -169,12 +168,24 @@ AnthropicOptionsT = TypeVar( # Translation between framework options keys and Anthropic Messages API OPTION_TRANSLATIONS: dict[str, str] = { - "model_id": "model", "stop": "stop_sequences", "instructions": "system", } +def _apply_option_translations(options: dict[str, Any]) -> None: + """Translate framework option keys to Anthropic request keys in-place. + + When both the old and new key are present, the new key wins and the old key + is discarded to preserve explicit overrides. + """ + for old_key, new_key in OPTION_TRANSLATIONS.items(): + if old_key not in options or old_key == new_key: + continue + old_value = options.pop(old_key) + options.setdefault(new_key, old_value) + + # region Role and Finish Reason Maps @@ -204,11 +215,11 @@ class AnthropicSettings(TypedDict, total=False): Keys: api_key: The Anthropic API key. - chat_model_id: The Anthropic chat model ID. + chat_model: The Anthropic chat model. """ api_key: SecretString | None - chat_model_id: str | None + chat_model: str | None class RawAnthropicClient( @@ -236,8 +247,8 @@ class RawAnthropicClient( self, *, api_key: str | None = None, - model_id: str | None = None, - anthropic_client: AsyncAnthropic | None = None, + model: str | None = None, + anthropic_client: AnthropicAsyncClient | None = None, additional_beta_flags: list[str] | None = None, additional_properties: dict[str, Any] | None = None, env_file_path: str | None = None, @@ -247,7 +258,7 @@ class RawAnthropicClient( Keyword Args: api_key: The Anthropic API key to use for authentication. - model_id: The ID of the model to use. + model: The model to use. anthropic_client: An existing Anthropic client to use. If not provided, one will be created. This can be used to further configure the client before passing it in. For instance if you need to set a different base_url for testing or private deployments. @@ -265,11 +276,11 @@ class RawAnthropicClient( # Using environment variables # Set ANTHROPIC_API_KEY=your_anthropic_api_key - # ANTHROPIC_CHAT_MODEL_ID=claude-sonnet-4-5-20250929 + # ANTHROPIC_CHAT_MODEL=claude-sonnet-4-5-20250929 # Or passing parameters directly client = RawAnthropicClient( - model_id="claude-sonnet-4-5-20250929", + model="claude-sonnet-4-5-20250929", api_key="your_anthropic_api_key", ) @@ -283,7 +294,7 @@ class RawAnthropicClient( api_key="your_anthropic_api_key", base_url="https://custom-anthropic-endpoint.com" ) client = RawAnthropicClient( - model_id="claude-sonnet-4-5-20250929", + model="claude-sonnet-4-5-20250929", anthropic_client=anthropic_client, ) @@ -296,7 +307,7 @@ class RawAnthropicClient( my_custom_option: str - client: RawAnthropicClient[MyOptions] = RawAnthropicClient(model_id="claude-sonnet-4-5-20250929") + client: RawAnthropicClient[MyOptions] = RawAnthropicClient(model="claude-sonnet-4-5-20250929") response = await client.get_response("Hello", options={"my_custom_option": "value"}) """ @@ -304,13 +315,13 @@ class RawAnthropicClient( AnthropicSettings, env_prefix="ANTHROPIC_", api_key=api_key, - chat_model_id=model_id, + chat_model=model, env_file_path=env_file_path, env_file_encoding=env_file_encoding, ) api_key_secret = anthropic_settings.get("api_key") - model_id_setting = anthropic_settings.get("chat_model_id") + model_setting = anthropic_settings.get("chat_model") if anthropic_client is None: if api_key_secret is None: @@ -332,7 +343,7 @@ class RawAnthropicClient( # Initialize instance variables self.anthropic_client = anthropic_client self.additional_beta_flags = additional_beta_flags or [] - self.model_id = model_id_setting + self.model = model_setting # streaming requires tracking the last function call ID, name, and content type self._last_call_id_name: tuple[str, str] | None = None self._last_call_content_type: str | None = None @@ -513,7 +524,7 @@ class RawAnthropicClient( if stream: # Streaming mode async def _stream() -> AsyncIterable[ChatResponseUpdate]: - async for chunk in await self.anthropic_client.beta.messages.create(**run_options, stream=True): + async for chunk in await self.anthropic_client.beta.messages.create(**run_options, stream=True): # type: ignore[misc] parsed_chunk = self._process_stream_event(chunk) if parsed_chunk: yield parsed_chunk @@ -522,7 +533,7 @@ class RawAnthropicClient( # Non-streaming mode async def _get_response() -> ChatResponse: - message = await self.anthropic_client.beta.messages.create(**run_options, stream=False) + message = await self.anthropic_client.beta.messages.create(**run_options, stream=False) # type: ignore[misc] return self._process_message(message, options) return _get_response() @@ -561,16 +572,22 @@ class RawAnthropicClient( # Stream mode is controlled explicitly at call sites. run_options.pop("stream", None) - # Translation between options keys and Anthropic Messages API - for old_key, new_key in OPTION_TRANSLATIONS.items(): - if old_key in run_options and old_key != new_key: - run_options[new_key] = run_options.pop(old_key) + _apply_option_translations(run_options) - # model id + # Filter out framework kwargs that should not be passed to the Anthropic API. + # This includes underscore-prefixed internal objects (like _function_middleware_pipeline) + # and framework kwargs like 'thread' and 'middleware'. + filtered_kwargs = { + k: v for k, v in kwargs.items() if not k.startswith("_") and k not in {"thread", "middleware"} + } + _apply_option_translations(filtered_kwargs) + run_options.update(filtered_kwargs) + + # model if not run_options.get("model"): - if not self.model_id: - raise ValueError("model_id must be a non-empty string") - run_options["model"] = self.model_id + if not self.model: + raise ValueError("model must be a non-empty string") + run_options["model"] = self.model # max_tokens - Anthropic requires this, default if not provided if not run_options.get("max_tokens"): @@ -607,13 +624,6 @@ class RawAnthropicClient( # Add the structured outputs beta flag run_options["betas"].add(STRUCTURED_OUTPUTS_BETA_FLAG) - # Filter out framework kwargs that should not be passed to the Anthropic API. - # This includes underscore-prefixed internal objects (like _function_middleware_pipeline) - # and framework kwargs like 'thread' and 'middleware'. - filtered_kwargs = { - k: v for k, v in kwargs.items() if not k.startswith("_") and k not in {"thread", "middleware"} - } - run_options.update(filtered_kwargs) return run_options def _prepare_betas(self, options: Mapping[str, Any]) -> set[str]: @@ -918,7 +928,7 @@ class RawAnthropicClient( ) ], usage_details=self._parse_usage_from_anthropic(message.usage), - model_id=message.model, + model=message.model, finish_reason=FINISH_REASON_MAP.get(message.stop_reason) if message.stop_reason else None, response_format=options.get("response_format"), raw_representation=message, @@ -946,7 +956,7 @@ class RawAnthropicClient( *self._parse_contents_from_anthropic(event.message.content), *usage_details, ], - model_id=event.message.model, + model=event.message.model, finish_reason=FINISH_REASON_MAP.get(event.message.stop_reason) if event.message.stop_reason else None, @@ -1396,8 +1406,8 @@ class AnthropicClient( self, *, api_key: str | None = None, - model_id: str | None = None, - anthropic_client: AsyncAnthropic | None = None, + model: str | None = None, + anthropic_client: AnthropicAsyncClient | None = None, additional_beta_flags: list[str] | None = None, additional_properties: dict[str, Any] | None = None, middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None, @@ -1409,7 +1419,7 @@ class AnthropicClient( Keyword Args: api_key: The Anthropic API key to use for authentication. - model_id: The ID of the model to use. + model: The model to use. anthropic_client: An existing Anthropic client to use. If not provided, one will be created. This can be used to further configure the client before passing it in. For instance if you need to set a different base_url for testing or private deployments. @@ -1428,11 +1438,11 @@ class AnthropicClient( # Using environment variables # Set ANTHROPIC_API_KEY=your_anthropic_api_key - # ANTHROPIC_CHAT_MODEL_ID=claude-sonnet-4-5-20250929 + # ANTHROPIC_CHAT_MODEL=claude-sonnet-4-5-20250929 # Or passing parameters directly client = AnthropicClient( - model_id="claude-sonnet-4-5-20250929", + model="claude-sonnet-4-5-20250929", api_key="your_anthropic_api_key", ) @@ -1446,7 +1456,7 @@ class AnthropicClient( api_key="your_anthropic_api_key", base_url="https://custom-anthropic-endpoint.com" ) client = AnthropicClient( - model_id="claude-sonnet-4-5-20250929", + model="claude-sonnet-4-5-20250929", anthropic_client=anthropic_client, ) @@ -1459,12 +1469,12 @@ class AnthropicClient( my_custom_option: str - client: AnthropicClient[MyOptions] = AnthropicClient(model_id="claude-sonnet-4-5-20250929") + client: AnthropicClient[MyOptions] = AnthropicClient(model="claude-sonnet-4-5-20250929") response = await client.get_response("Hello", options={"my_custom_option": "value"}) """ super().__init__( api_key=api_key, - model_id=model_id, + model=model, anthropic_client=anthropic_client, additional_beta_flags=additional_beta_flags, additional_properties=additional_properties, diff --git a/python/packages/anthropic/agent_framework_anthropic/_foundry_client.py b/python/packages/anthropic/agent_framework_anthropic/_foundry_client.py new file mode 100644 index 0000000000..f5fe37296f --- /dev/null +++ b/python/packages/anthropic/agent_framework_anthropic/_foundry_client.py @@ -0,0 +1,166 @@ +# Copyright (c) Microsoft. All rights reserved. + +from __future__ import annotations + +from collections.abc import Awaitable, Callable, Sequence +from typing import Any, ClassVar, Generic, TypedDict + +from agent_framework import ( + AGENT_FRAMEWORK_USER_AGENT, + ChatAndFunctionMiddlewareTypes, + ChatMiddlewareLayer, + FunctionInvocationConfiguration, + FunctionInvocationLayer, +) +from agent_framework._settings import SecretString, load_settings +from agent_framework.observability import ChatTelemetryLayer +from anthropic import AsyncAnthropicFoundry + +from ._chat_client import AnthropicOptionsT, RawAnthropicClient + +AnthropicFoundryAzureADTokenProvider = Callable[[], str | Awaitable[str]] + + +class AnthropicFoundrySettings(TypedDict, total=False): + """Resolved settings for Anthropic Foundry wrappers.""" + + anthropic_foundry_api_key: SecretString | None + anthropic_foundry_resource: str | None + anthropic_foundry_base_url: str | None + anthropic_chat_model: str | None + + +class RawAnthropicFoundryClient(RawAnthropicClient[AnthropicOptionsT], Generic[AnthropicOptionsT]): + """Raw Anthropic Foundry chat client without middleware, telemetry, or function invocation support.""" + + OTEL_PROVIDER_NAME: ClassVar[str] = "azure.ai.foundry" # type: ignore[reportIncompatibleVariableOverride, misc] + + def __init__( + self, + *, + model: str | None = None, + resource: str | None = None, + api_key: str | None = None, + azure_ad_token_provider: AnthropicFoundryAzureADTokenProvider | None = None, + base_url: str | None = None, + anthropic_client: AsyncAnthropicFoundry | None = None, + additional_beta_flags: list[str] | None = None, + additional_properties: dict[str, Any] | None = None, + env_file_path: str | None = None, + env_file_encoding: str | None = None, + ) -> None: + """Initialize a raw Anthropic Foundry client. + + Keyword Args: + model: The Anthropic model to use. + resource: The Foundry resource name. + api_key: The Foundry Anthropic API key. + azure_ad_token_provider: Azure AD token provider used by the Anthropic SDK. + base_url: Full Anthropic-compatible Foundry base URL. + anthropic_client: Existing AsyncAnthropicFoundry client to reuse. + additional_beta_flags: Additional beta flags to enable on the client. + additional_properties: Additional properties stored on the client instance. + env_file_path: Path to environment file for loading settings. + env_file_encoding: Encoding of the environment file. + """ + settings = load_settings( + AnthropicFoundrySettings, + env_prefix="", + anthropic_foundry_api_key=api_key, + anthropic_foundry_resource=resource, + anthropic_foundry_base_url=base_url, + anthropic_chat_model=model, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) + api_key_secret = settings.get("anthropic_foundry_api_key") + model_setting = settings.get("anthropic_chat_model") + resource_setting = settings.get("anthropic_foundry_resource") + base_url_setting = settings.get("anthropic_foundry_base_url") + api_key_value = api_key_secret.get_secret_value() if api_key_secret is not None else None + + if anthropic_client is None: + if base_url_setting is None and resource_setting is None: + message = ( + "Anthropic Foundry requires either `resource`/`ANTHROPIC_FOUNDRY_RESOURCE` " + "or `base_url`/`ANTHROPIC_FOUNDRY_BASE_URL`." + ) + raise ValueError(message) + if base_url_setting is not None: + anthropic_client = AsyncAnthropicFoundry( + base_url=base_url_setting, + api_key=api_key_value, + azure_ad_token_provider=azure_ad_token_provider, + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + else: + anthropic_client = AsyncAnthropicFoundry( + resource=resource_setting, + api_key=api_key_value, + azure_ad_token_provider=azure_ad_token_provider, + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + + super().__init__( + model=model_setting, + anthropic_client=anthropic_client, + additional_beta_flags=additional_beta_flags, + additional_properties=additional_properties, + ) + + +class AnthropicFoundryClient( # type: ignore[misc] + FunctionInvocationLayer[AnthropicOptionsT], + ChatMiddlewareLayer[AnthropicOptionsT], + ChatTelemetryLayer[AnthropicOptionsT], + RawAnthropicFoundryClient[AnthropicOptionsT], + Generic[AnthropicOptionsT], +): + """Anthropic Foundry chat client with middleware, telemetry, and function invocation support.""" + + def __init__( + self, + *, + model: str | None = None, + resource: str | None = None, + api_key: str | None = None, + azure_ad_token_provider: AnthropicFoundryAzureADTokenProvider | None = None, + base_url: str | None = None, + anthropic_client: AsyncAnthropicFoundry | None = None, + additional_beta_flags: list[str] | None = None, + additional_properties: dict[str, Any] | None = None, + middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None, + function_invocation_configuration: FunctionInvocationConfiguration | None = None, + env_file_path: str | None = None, + env_file_encoding: str | None = None, + ) -> None: + """Initialize an Anthropic Foundry client. + + Keyword Args: + model: The Anthropic model to use. + resource: The Foundry resource name. + api_key: The Foundry Anthropic API key. + azure_ad_token_provider: Azure AD token provider used by the Anthropic SDK. + base_url: Full Anthropic-compatible Foundry base URL. + anthropic_client: Existing AsyncAnthropicFoundry client to reuse. + additional_beta_flags: Additional beta flags to enable on the client. + additional_properties: Additional properties stored on the client instance. + middleware: Optional middleware to apply to the client. + function_invocation_configuration: Optional function invocation configuration override. + env_file_path: Path to environment file for loading settings. + env_file_encoding: Encoding of the environment file. + """ + super().__init__( + model=model, + resource=resource, + api_key=api_key, + azure_ad_token_provider=azure_ad_token_provider, + base_url=base_url, + anthropic_client=anthropic_client, + additional_beta_flags=additional_beta_flags, + additional_properties=additional_properties, + middleware=middleware, + function_invocation_configuration=function_invocation_configuration, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) diff --git a/python/packages/anthropic/agent_framework_anthropic/_vertex_client.py b/python/packages/anthropic/agent_framework_anthropic/_vertex_client.py new file mode 100644 index 0000000000..73b16af4a7 --- /dev/null +++ b/python/packages/anthropic/agent_framework_anthropic/_vertex_client.py @@ -0,0 +1,160 @@ +# Copyright (c) Microsoft. All rights reserved. + +from __future__ import annotations + +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypedDict + +from agent_framework import ( + AGENT_FRAMEWORK_USER_AGENT, + ChatAndFunctionMiddlewareTypes, + ChatMiddlewareLayer, + FunctionInvocationConfiguration, + FunctionInvocationLayer, +) +from agent_framework._settings import load_settings +from agent_framework.observability import ChatTelemetryLayer +from anthropic import NOT_GIVEN, AsyncAnthropicVertex + +from ._chat_client import AnthropicOptionsT, RawAnthropicClient + +if TYPE_CHECKING: + from google.auth.credentials import Credentials as GoogleCredentials + + +class AnthropicVertexSettings(TypedDict, total=False): + """Resolved settings for Anthropic Vertex wrappers.""" + + cloud_ml_region: str | None + anthropic_vertex_project_id: str | None + anthropic_vertex_base_url: str | None + anthropic_chat_model: str | None + + +class RawAnthropicVertexClient(RawAnthropicClient[AnthropicOptionsT], Generic[AnthropicOptionsT]): + """Raw Anthropic Vertex chat client without middleware, telemetry, or function invocation support.""" + + OTEL_PROVIDER_NAME: ClassVar[str] = "google.vertex.ai" # type: ignore[reportIncompatibleVariableOverride, misc] + + def __init__( + self, + *, + model: str | None = None, + region: str | None = None, + project_id: str | None = None, + access_token: str | None = None, + credentials: GoogleCredentials | None = None, + base_url: str | None = None, + anthropic_client: AsyncAnthropicVertex | None = None, + additional_beta_flags: list[str] | None = None, + additional_properties: dict[str, Any] | None = None, + env_file_path: str | None = None, + env_file_encoding: str | None = None, + ) -> None: + """Initialize a raw Anthropic Vertex client. + + Keyword Args: + model: The Anthropic model to use. + region: Vertex region. Falls back to `CLOUD_ML_REGION`. + project_id: Vertex project ID. Falls back to `ANTHROPIC_VERTEX_PROJECT_ID`. + access_token: Explicit OAuth access token. + credentials: Google credentials object. + base_url: Optional custom Anthropic Vertex base URL. + anthropic_client: Existing AsyncAnthropicVertex client to reuse. + additional_beta_flags: Additional beta flags to enable on the client. + additional_properties: Additional properties stored on the client instance. + env_file_path: Path to environment file for loading settings. + env_file_encoding: Encoding of the environment file. + """ + settings = load_settings( + AnthropicVertexSettings, + env_prefix="", + cloud_ml_region=region, + anthropic_vertex_project_id=project_id, + anthropic_vertex_base_url=base_url, + anthropic_chat_model=model, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) + model_setting = settings.get("anthropic_chat_model") + region_setting = settings.get("cloud_ml_region") + project_id_setting = settings.get("anthropic_vertex_project_id") + + if anthropic_client is None: + resolved_region = region_setting if region_setting is not None else NOT_GIVEN + resolved_project_id = project_id_setting if project_id_setting is not None else NOT_GIVEN + anthropic_client = AsyncAnthropicVertex( + region=resolved_region, + project_id=resolved_project_id, + access_token=access_token, + credentials=credentials, + base_url=settings.get("anthropic_vertex_base_url"), + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + + super().__init__( + model=model_setting, + anthropic_client=anthropic_client, + additional_beta_flags=additional_beta_flags, + additional_properties=additional_properties, + ) + + +class AnthropicVertexClient( # type: ignore[misc] + FunctionInvocationLayer[AnthropicOptionsT], + ChatMiddlewareLayer[AnthropicOptionsT], + ChatTelemetryLayer[AnthropicOptionsT], + RawAnthropicVertexClient[AnthropicOptionsT], + Generic[AnthropicOptionsT], +): + """Anthropic Vertex chat client with middleware, telemetry, and function invocation support.""" + + def __init__( + self, + *, + model: str | None = None, + region: str | None = None, + project_id: str | None = None, + access_token: str | None = None, + credentials: GoogleCredentials | None = None, + base_url: str | None = None, + anthropic_client: AsyncAnthropicVertex | None = None, + additional_beta_flags: list[str] | None = None, + additional_properties: dict[str, Any] | None = None, + middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None, + function_invocation_configuration: FunctionInvocationConfiguration | None = None, + env_file_path: str | None = None, + env_file_encoding: str | None = None, + ) -> None: + """Initialize an Anthropic Vertex client. + + Keyword Args: + model: The Anthropic model to use. + region: Vertex region. Falls back to `CLOUD_ML_REGION`. + project_id: Vertex project ID. Falls back to `ANTHROPIC_VERTEX_PROJECT_ID`. + access_token: Explicit OAuth access token. + credentials: Google credentials object. + base_url: Optional custom Anthropic Vertex base URL. + anthropic_client: Existing AsyncAnthropicVertex client to reuse. + additional_beta_flags: Additional beta flags to enable on the client. + additional_properties: Additional properties stored on the client instance. + middleware: Optional middleware to apply to the client. + function_invocation_configuration: Optional function invocation configuration override. + env_file_path: Path to environment file for loading settings. + env_file_encoding: Encoding of the environment file. + """ + super().__init__( + model=model, + region=region, + project_id=project_id, + access_token=access_token, + credentials=credentials, + base_url=base_url, + anthropic_client=anthropic_client, + additional_beta_flags=additional_beta_flags, + additional_properties=additional_properties, + middleware=middleware, + function_invocation_configuration=function_invocation_configuration, + env_file_path=env_file_path, + env_file_encoding=env_file_encoding, + ) diff --git a/python/packages/anthropic/tests/conftest.py b/python/packages/anthropic/tests/conftest.py index a2313f4d39..bbe92abea8 100644 --- a/python/packages/anthropic/tests/conftest.py +++ b/python/packages/anthropic/tests/conftest.py @@ -28,7 +28,7 @@ def anthropic_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): env_vars = { "ANTHROPIC_API_KEY": "test-api-key-12345", - "ANTHROPIC_CHAT_MODEL_ID": "claude-3-5-sonnet-20241022", + "ANTHROPIC_CHAT_MODEL": "claude-3-5-sonnet-20241022", } env_vars.update(override_env_param_dict) # type: ignore diff --git a/python/packages/anthropic/tests/test_anthropic_client.py b/python/packages/anthropic/tests/test_anthropic_client.py index 258cc275ca..b9e3689e85 100644 --- a/python/packages/anthropic/tests/test_anthropic_client.py +++ b/python/packages/anthropic/tests/test_anthropic_client.py @@ -40,7 +40,7 @@ skip_if_anthropic_integration_tests_disabled = pytest.mark.skipif( def create_test_anthropic_client( mock_anthropic_client: MagicMock, - model_id: str | None = None, + model: str | None = None, anthropic_settings: AnthropicSettings | None = None, ) -> AnthropicClient: """Helper function to create AnthropicClient instances for testing, bypassing normal validation.""" @@ -51,7 +51,7 @@ def create_test_anthropic_client( AnthropicSettings, env_prefix="ANTHROPIC_", api_key="test-api-key-12345", - chat_model_id="claude-3-5-sonnet-20241022", + chat_model="claude-3-5-sonnet-20241022", ) # Create client instance directly @@ -59,7 +59,7 @@ def create_test_anthropic_client( # Set attributes directly client.anthropic_client = mock_anthropic_client - client.model_id = model_id or anthropic_settings["chat_model_id"] + client.model = model or anthropic_settings["chat_model"] client._last_call_id_name = None client._tool_name_aliases = {} client.additional_properties = {} @@ -83,7 +83,7 @@ def test_anthropic_settings_init(anthropic_unit_test_env: dict[str, str]) -> Non assert settings["api_key"] is not None assert settings["api_key"].get_secret_value() == anthropic_unit_test_env["ANTHROPIC_API_KEY"] - assert settings["chat_model_id"] == anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL_ID"] + assert settings["chat_model"] == anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL"] def test_anthropic_settings_init_with_explicit_values() -> None: @@ -92,12 +92,12 @@ def test_anthropic_settings_init_with_explicit_values() -> None: AnthropicSettings, env_prefix="ANTHROPIC_", api_key="custom-api-key", - chat_model_id="claude-3-opus-20240229", + chat_model="claude-3-opus-20240229", ) assert settings["api_key"] is not None assert settings["api_key"].get_secret_value() == "custom-api-key" - assert settings["chat_model_id"] == "claude-3-opus-20240229" + assert settings["chat_model"] == "claude-3-opus-20240229" @pytest.mark.parametrize("exclude_list", [["ANTHROPIC_API_KEY"]], indirect=True) @@ -107,7 +107,7 @@ def test_anthropic_settings_missing_api_key( """Test AnthropicSettings when API key is missing.""" settings = load_settings(AnthropicSettings, env_prefix="ANTHROPIC_") assert settings["api_key"] is None - assert settings["chat_model_id"] == anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL_ID"] + assert settings["chat_model"] == anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL"] # Client Initialization Tests @@ -115,10 +115,10 @@ def test_anthropic_settings_missing_api_key( def test_anthropic_client_init_with_client(mock_anthropic_client: MagicMock) -> None: """Test AnthropicClient initialization with existing anthropic_client.""" - client = create_test_anthropic_client(mock_anthropic_client, model_id="claude-3-5-sonnet-20241022") + client = create_test_anthropic_client(mock_anthropic_client, model="claude-3-5-sonnet-20241022") assert client.anthropic_client is mock_anthropic_client - assert client.model_id == "claude-3-5-sonnet-20241022" + assert client.model == "claude-3-5-sonnet-20241022" assert isinstance(client, SupportsChatGetResponse) @@ -141,11 +141,11 @@ def test_anthropic_client_init_auto_create_client( """Test AnthropicClient initialization with auto-created anthropic_client.""" client = AnthropicClient( api_key=anthropic_unit_test_env["ANTHROPIC_API_KEY"], - model_id=anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL_ID"], + model=anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL"], ) assert client.anthropic_client is not None - assert client.model_id == anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL_ID"] + assert client.model == anthropic_unit_test_env["ANTHROPIC_CHAT_MODEL"] def test_anthropic_client_init_missing_api_key() -> None: @@ -153,7 +153,7 @@ def test_anthropic_client_init_missing_api_key() -> None: with patch("agent_framework_anthropic._chat_client.load_settings") as mock_load: mock_load.return_value = { "api_key": None, - "chat_model_id": "claude-3-5-sonnet-20241022", + "chat_model": "claude-3-5-sonnet-20241022", } with pytest.raises(ValueError, match="Anthropic API key is required"): @@ -740,7 +740,7 @@ async def test_prepare_options_basic(mock_anthropic_client: MagicMock) -> None: run_options = client._prepare_options(messages, chat_options) - assert run_options["model"] == client.model_id + assert run_options["model"] == client.model assert run_options["max_tokens"] == 100 assert run_options["temperature"] == 0.7 assert "messages" in run_options @@ -980,7 +980,7 @@ def test_process_message_basic(mock_anthropic_client: MagicMock) -> None: response = client._process_message(mock_message, {}) assert response.response_id == "msg_123" - assert response.model_id == "claude-3-5-sonnet-20241022" + assert response.model == "claude-3-5-sonnet-20241022" assert len(response.messages) == 1 assert response.messages[0].role == "assistant" assert len(response.messages[0].contents) == 1 @@ -2036,10 +2036,10 @@ def test_prepare_options_with_instructions(mock_anthropic_client: MagicMock) -> assert result["max_tokens"] == 1024 -def test_prepare_options_missing_model_id(mock_anthropic_client: MagicMock) -> None: - """Test prepare_options raises error when model_id is missing.""" +def test_prepare_options_missing_model(mock_anthropic_client: MagicMock) -> None: + """Test prepare_options raises error when model is missing.""" client = create_test_anthropic_client(mock_anthropic_client) - client.model_id = "" # Set empty model_id + client.model = "" # Set empty model messages = [Message(role="user", contents=[Content.from_text("Hello")])] options = {} @@ -2048,7 +2048,31 @@ def test_prepare_options_missing_model_id(mock_anthropic_client: MagicMock) -> N client._prepare_options(messages, options) raise AssertionError("Expected ValueError") except ValueError as e: - assert "model_id must be a non-empty string" in str(e) + assert "model must be a non-empty string" in str(e) + + +def test_prepare_options_translates_model_option(mock_anthropic_client: MagicMock) -> None: + """Test prepare_options translates model to model for runtime option compatibility.""" + client = create_test_anthropic_client(mock_anthropic_client) + + messages = [Message(role="user", contents=[Content.from_text("Hello")])] + + result = client._prepare_options(messages, {"model": "claude-3-5-sonnet-20241022"}) + + assert result["model"] == "claude-3-5-sonnet-20241022" + assert "model_id" not in result + + +def test_prepare_options_translates_model_kwarg(mock_anthropic_client: MagicMock) -> None: + """Test prepare_options translates model passed as a direct keyword argument.""" + client = create_test_anthropic_client(mock_anthropic_client) + + messages = [Message(role="user", contents=[Content.from_text("Hello")])] + + result = client._prepare_options(messages, {}, model="claude-3-5-sonnet-20241022") + + assert result["model"] == "claude-3-5-sonnet-20241022" + assert "model_id" not in result def test_prepare_options_with_user_metadata(mock_anthropic_client: MagicMock) -> None: diff --git a/python/packages/anthropic/tests/test_anthropic_provider_clients.py b/python/packages/anthropic/tests/test_anthropic_provider_clients.py new file mode 100644 index 0000000000..d076062fe6 --- /dev/null +++ b/python/packages/anthropic/tests/test_anthropic_provider_clients.py @@ -0,0 +1,156 @@ +# Copyright (c) Microsoft. All rights reserved. + +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest +from agent_framework import AGENT_FRAMEWORK_USER_AGENT, ChatMiddlewareLayer, FunctionInvocationLayer +from agent_framework.observability import ChatTelemetryLayer + +from agent_framework_anthropic import ( + AnthropicBedrockClient, + AnthropicFoundryClient, + AnthropicVertexClient, + RawAnthropicBedrockClient, + RawAnthropicFoundryClient, + RawAnthropicVertexClient, +) + + +def _create_mock_transport(base_url: str) -> MagicMock: + transport = MagicMock() + transport.base_url = base_url + transport.beta = MagicMock() + transport.beta.messages = MagicMock() + transport.beta.messages.create = AsyncMock() + return transport + + +@pytest.mark.parametrize( + ("public_client", "raw_client"), + [ + (AnthropicFoundryClient, RawAnthropicFoundryClient), + (AnthropicBedrockClient, RawAnthropicBedrockClient), + (AnthropicVertexClient, RawAnthropicVertexClient), + ], +) +def test_provider_client_wraps_raw_client_with_standard_layer_order(public_client, raw_client) -> None: + assert issubclass(public_client, raw_client) + mro = public_client.__mro__ + assert mro.index(FunctionInvocationLayer) < mro.index(ChatMiddlewareLayer) + assert mro.index(ChatMiddlewareLayer) < mro.index(ChatTelemetryLayer) + assert mro.index(ChatTelemetryLayer) < mro.index(raw_client) + + +def test_raw_anthropic_foundry_client_creates_sdk_client_from_settings(tmp_path) -> None: + env_file = tmp_path / ".env" + env_file.write_text( + "ANTHROPIC_CHAT_MODEL=claude-foundry-test\n" + "ANTHROPIC_FOUNDRY_API_KEY=test-key\n" + "ANTHROPIC_FOUNDRY_RESOURCE=test-resource\n" + ) + mock_transport = _create_mock_transport("https://test-resource.services.ai.azure.com/anthropic/") + + with patch( + "agent_framework_anthropic._foundry_client.AsyncAnthropicFoundry", return_value=mock_transport + ) as factory: + client = RawAnthropicFoundryClient(env_file_path=str(env_file)) + + assert client.model == "claude-foundry-test" + assert client.anthropic_client is mock_transport + factory.assert_called_once_with( + resource="test-resource", + api_key="test-key", + azure_ad_token_provider=None, + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + + +def test_raw_anthropic_foundry_client_creates_sdk_client_from_base_url_settings(tmp_path) -> None: + env_file = tmp_path / ".env" + env_file.write_text( + "ANTHROPIC_CHAT_MODEL=claude-foundry-test\n" + "ANTHROPIC_FOUNDRY_API_KEY=test-key\n" + "ANTHROPIC_FOUNDRY_BASE_URL=https://test-resource.services.ai.azure.com/anthropic/\n" + ) + mock_transport = _create_mock_transport("https://test-resource.services.ai.azure.com/anthropic/") + + with patch( + "agent_framework_anthropic._foundry_client.AsyncAnthropicFoundry", return_value=mock_transport + ) as factory: + client = RawAnthropicFoundryClient(env_file_path=str(env_file)) + + assert client.model == "claude-foundry-test" + assert client.anthropic_client is mock_transport + factory.assert_called_once_with( + base_url="https://test-resource.services.ai.azure.com/anthropic/", + api_key="test-key", + azure_ad_token_provider=None, + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + + +def test_raw_anthropic_foundry_client_requires_resource_or_base_url() -> None: + with patch("agent_framework_anthropic._foundry_client.load_settings") as mock_load: + mock_load.return_value = { + "anthropic_foundry_api_key": None, + "anthropic_foundry_resource": None, + "anthropic_foundry_base_url": None, + "anthropic_chat_model": None, + } + + with pytest.raises( + ValueError, + match=( + "Anthropic Foundry requires either `resource`/`ANTHROPIC_FOUNDRY_RESOURCE` " + "or `base_url`/`ANTHROPIC_FOUNDRY_BASE_URL`\\." + ), + ): + RawAnthropicFoundryClient() + + +def test_raw_anthropic_bedrock_client_creates_sdk_client_from_arguments() -> None: + mock_transport = _create_mock_transport("https://bedrock-runtime.us-east-1.amazonaws.com") + + with patch( + "agent_framework_anthropic._bedrock_client.AsyncAnthropicBedrock", return_value=mock_transport + ) as factory: + client = RawAnthropicBedrockClient( + model="claude-bedrock-test", + aws_access_key="access-key", + aws_secret_key="secret-key", + aws_region="us-east-1", + ) + + assert client.model == "claude-bedrock-test" + assert client.anthropic_client is mock_transport + factory.assert_called_once_with( + aws_secret_key="secret-key", + aws_access_key="access-key", + aws_region="us-east-1", + aws_profile=None, + aws_session_token=None, + base_url=None, + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) + + +def test_raw_anthropic_vertex_client_creates_sdk_client_from_arguments() -> None: + mock_transport = _create_mock_transport("https://us-central1-aiplatform.googleapis.com/v1") + + with patch("agent_framework_anthropic._vertex_client.AsyncAnthropicVertex", return_value=mock_transport) as factory: + client = RawAnthropicVertexClient( + model="claude-vertex-test", + region="us-central1", + project_id="test-project", + ) + + assert client.model == "claude-vertex-test" + assert client.anthropic_client is mock_transport + factory.assert_called_once_with( + region="us-central1", + project_id="test-project", + access_token=None, + credentials=None, + base_url=None, + default_headers={"User-Agent": AGENT_FRAMEWORK_USER_AGENT}, + ) diff --git a/python/packages/azure-ai-search/agent_framework_azure_ai_search/_context_provider.py b/python/packages/azure-ai-search/agent_framework_azure_ai_search/_context_provider.py index c10e7cb9b8..f27df92a7b 100644 --- a/python/packages/azure-ai-search/agent_framework_azure_ai_search/_context_provider.py +++ b/python/packages/azure-ai-search/agent_framework_azure_ai_search/_context_provider.py @@ -180,8 +180,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: EmbeddingFunction | None = None, context_prompt: str | None = None, azure_openai_resource_url: str | None = None, - model_deployment_name: str | None = None, - model_name: str | None = None, + model: str | None = None, knowledge_base_name: None = None, retrieval_instructions: str | None = None, azure_openai_api_key: str | None = None, @@ -206,8 +205,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: Embedding provider used for vector search. context_prompt: Custom prompt to prepend to retrieved context. azure_openai_resource_url: Unused in semantic mode. - model_deployment_name: Unused in semantic mode. - model_name: Unused in semantic mode. + model: Unused in semantic mode. knowledge_base_name: Must be ``None`` for this overload. retrieval_instructions: Unused in semantic mode. azure_openai_api_key: Unused in semantic mode. @@ -235,8 +233,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: EmbeddingFunction | None = None, context_prompt: str | None = None, azure_openai_resource_url: str, - model_deployment_name: str, - model_name: str | None = None, + model: str, knowledge_base_name: None = None, retrieval_instructions: str | None = None, azure_openai_api_key: str | None = None, @@ -261,8 +258,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: Embedding provider used for vector search. context_prompt: Custom prompt to prepend to retrieved context. azure_openai_resource_url: Azure OpenAI resource URL for Knowledge Base creation. - model_deployment_name: Azure OpenAI deployment used by the generated Knowledge Base. - model_name: Underlying model name for the Knowledge Base model configuration. + model: Model used by the generated Knowledge Base. knowledge_base_name: Must be ``None`` for this overload. retrieval_instructions: Custom instructions for Knowledge Base retrieval. azure_openai_api_key: Optional Azure OpenAI API key for Knowledge Base creation. @@ -290,8 +286,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: EmbeddingFunction | None = None, context_prompt: str | None = None, azure_openai_resource_url: str | None = None, - model_deployment_name: str | None = None, - model_name: str | None = None, + model: str | None = None, knowledge_base_name: str, retrieval_instructions: str | None = None, azure_openai_api_key: str | None = None, @@ -317,8 +312,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: Embedding provider used for vector search. context_prompt: Custom prompt to prepend to retrieved context. azure_openai_resource_url: Unused when connecting to an existing Knowledge Base. - model_deployment_name: Unused when connecting to an existing Knowledge Base. - model_name: Unused when connecting to an existing Knowledge Base. + model: Unused when connecting to an existing Knowledge Base. retrieval_instructions: Custom instructions for Knowledge Base retrieval. azure_openai_api_key: Unused when connecting to an existing Knowledge Base. knowledge_base_output_mode: Output mode for Knowledge Base retrieval. @@ -345,8 +339,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: EmbeddingFunction | None = None, context_prompt: str | None = None, azure_openai_resource_url: str | None = None, - model_deployment_name: str | None = None, - model_name: str | None = None, + model: str | None = None, knowledge_base_name: None = None, retrieval_instructions: str | None = None, azure_openai_api_key: str | None = None, @@ -375,8 +368,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: Embedding provider used for vector search. context_prompt: Custom prompt to prepend to retrieved context. azure_openai_resource_url: Azure OpenAI resource URL when creating a Knowledge Base from an index. - model_deployment_name: Azure OpenAI deployment when creating a Knowledge Base from an index. - model_name: Underlying model name for Knowledge Base model configuration. + model: Model used when creating a Knowledge Base from an index. knowledge_base_name: Resolved from ``env_file_path`` or ``AZURE_SEARCH_KNOWLEDGE_BASE_NAME``. retrieval_instructions: Custom instructions for Knowledge Base retrieval. azure_openai_api_key: Optional Azure OpenAI API key for Knowledge Base creation. @@ -403,8 +395,7 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: EmbeddingFunction | None = None, context_prompt: str | None = None, azure_openai_resource_url: str | None = None, - model_deployment_name: str | None = None, - model_name: str | None = None, + model: str | None = None, knowledge_base_name: str | None = None, retrieval_instructions: str | None = None, azure_openai_api_key: str | None = None, @@ -432,11 +423,8 @@ class AzureAISearchContextProvider(ContextProvider): embedding_function: Async function to generate embeddings or a SupportsGetEmbeddings instance. context_prompt: Custom prompt to prepend to retrieved context. azure_openai_resource_url: Azure OpenAI resource URL for Knowledge Base. - model_deployment_name: Model deployment name in Azure OpenAI. - model_name: The underlying model name. - knowledge_base_name: Name of an existing Knowledge Base to use. In agentic mode, - providing this explicitly selects the Knowledge Base-backed setup and ignores any - environment-provided index name. + model: Model name to use for Azure OpenAI vectorization. + knowledge_base_name: Name of an existing Knowledge Base to use. retrieval_instructions: Custom instructions for Knowledge Base retrieval. azure_openai_api_key: Azure OpenAI API key. knowledge_base_output_mode: Output mode for Knowledge Base retrieval. @@ -483,10 +471,8 @@ class AzureAISearchContextProvider(ContextProvider): if ignored_agentic_field is not None: settings[ignored_agentic_field] = None - if mode == "agentic" and settings.get("index_name") and not model_deployment_name: - raise ValueError( - "model_deployment_name is required for agentic mode when creating Knowledge Base from index." - ) + if mode == "agentic" and settings.get("index_name") and not model: + raise ValueError("model is required for agentic mode when creating Knowledge Base from index.") resolved_credential: AzureKeyCredential | AsyncTokenCredential if credential: @@ -512,8 +498,7 @@ class AzureAISearchContextProvider(ContextProvider): self.context_prompt = context_prompt or self._DEFAULT_SEARCH_CONTEXT_PROMPT self.azure_openai_resource_url = azure_openai_resource_url - self.azure_openai_deployment_name = model_deployment_name - self.model_name = model_name or model_deployment_name + self.azure_openai_model = model self.knowledge_base_name = settings.get("knowledge_base_name") self.retrieval_instructions = retrieval_instructions self.azure_openai_api_key = azure_openai_api_key @@ -762,8 +747,8 @@ class AzureAISearchContextProvider(ContextProvider): raise ValueError("Index client is required when creating Knowledge Base from index") if not self.azure_openai_resource_url: raise ValueError("azure_openai_resource_url is required when creating Knowledge Base from index") - if not self.azure_openai_deployment_name: - raise ValueError("model_deployment_name is required when creating Knowledge Base from index") + if not self.azure_openai_model: + raise ValueError("model is required when creating Knowledge Base from index") if not self.index_name: raise ValueError("index_name is required when creating Knowledge Base from index") @@ -782,8 +767,8 @@ class AzureAISearchContextProvider(ContextProvider): aoai_params = AzureOpenAIVectorizerParameters( resource_url=self.azure_openai_resource_url, - deployment_name=self.azure_openai_deployment_name, - model_name=self.model_name, + deployment_name=self.azure_openai_model, + model_name=self.azure_openai_model, api_key=self.azure_openai_api_key, ) diff --git a/python/packages/azure-ai-search/tests/test_aisearch_context_provider.py b/python/packages/azure-ai-search/tests/test_aisearch_context_provider.py index 6b87b502d9..945c5079f6 100644 --- a/python/packages/azure-ai-search/tests/test_aisearch_context_provider.py +++ b/python/packages/azure-ai-search/tests/test_aisearch_context_provider.py @@ -155,14 +155,14 @@ class TestInitSemantic: provider = _make_provider(context_prompt="Custom prompt:") assert provider.context_prompt == "Custom prompt:" - def test_model_name_falls_back_to_deployment_name(self) -> None: - """model_name defaults to model_deployment_name when not explicitly set.""" - provider = _make_provider(model_deployment_name="my-deploy") - assert provider.model_name == "my-deploy" + def test_model_is_stored(self) -> None: + """Model is stored on the provider for Azure OpenAI vectorization.""" + provider = _make_provider(model="my-deploy") + assert provider.azure_openai_model == "my-deploy" - def test_model_name_explicit(self) -> None: - provider = _make_provider(model_deployment_name="deploy", model_name="gpt-4") - assert provider.model_name == "gpt-4" + def test_model_explicit(self) -> None: + provider = _make_provider(model="gpt-4") + assert provider.azure_openai_model == "gpt-4" # -- Initialization: credential resolution ------------------------------------ @@ -214,7 +214,7 @@ class TestInitAgenticValidation: knowledge_base_name="kb", api_key="key", mode="agentic", - model_deployment_name="deploy", + model="deploy", azure_openai_resource_url="https://aoai.openai.azure.com", ) @@ -227,8 +227,8 @@ class TestInitAgenticValidation: mode="agentic", ) - def test_missing_model_deployment_name_raises(self) -> None: - with pytest.raises(ValueError, match="model_deployment_name"): + def test_missing_model_raises(self) -> None: + with pytest.raises(ValueError, match="model"): AzureAISearchContextProvider( source_id="s", endpoint="https://test.search.windows.net", @@ -256,7 +256,7 @@ class TestInitAgenticValidation: index_name="idx", api_key="key", mode="agentic", - model_deployment_name="deploy", + model="deploy", ) def test_agentic_with_kb_name_sets_use_existing(self) -> None: @@ -277,7 +277,7 @@ class TestInitAgenticValidation: index_name="idx", api_key="key", mode="agentic", - model_deployment_name="deploy", + model="deploy", azure_openai_resource_url="https://aoai.openai.azure.com", ) assert provider._use_existing_knowledge_base is False @@ -306,7 +306,7 @@ class TestInitAgenticValidation: index_name="idx", api_key="key", mode="agentic", - model_deployment_name="deploy", + model="deploy", azure_openai_resource_url="https://aoai.openai.azure.com", ) @@ -1011,9 +1011,9 @@ class TestEnsureKnowledgeBase: provider.knowledge_base_name = "test-kb" provider._index_client = AsyncMock() provider.azure_openai_resource_url = "https://aoai.openai.azure.com" - provider.azure_openai_deployment_name = None + provider.azure_openai_model = None - with pytest.raises(ValueError, match="model_deployment_name is required"): + with pytest.raises(ValueError, match="model is required"): await provider._ensure_knowledge_base() async def test_missing_index_name_raises(self) -> None: @@ -1023,7 +1023,7 @@ class TestEnsureKnowledgeBase: provider.knowledge_base_name = "test-kb" provider._index_client = AsyncMock() provider.azure_openai_resource_url = "https://aoai.openai.azure.com" - provider.azure_openai_deployment_name = "deploy" + provider.azure_openai_model = "deploy" provider.index_name = None with pytest.raises(ValueError, match="index_name is required"): @@ -1037,8 +1037,7 @@ class TestEnsureKnowledgeBase: provider._use_existing_knowledge_base = False provider.knowledge_base_name = "test-kb" provider.azure_openai_resource_url = "https://aoai.openai.azure.com" - provider.azure_openai_deployment_name = "deploy" - provider.model_name = "gpt-4" + provider.azure_openai_model = "gpt-4" provider.index_name = "test-index" mock_index_client = AsyncMock() @@ -1061,8 +1060,7 @@ class TestEnsureKnowledgeBase: provider._use_existing_knowledge_base = False provider.knowledge_base_name = "test-kb" provider.azure_openai_resource_url = "https://aoai.openai.azure.com" - provider.azure_openai_deployment_name = "deploy" - provider.model_name = "gpt-4" + provider.azure_openai_model = "gpt-4" provider.index_name = "test-index" mock_index_client = AsyncMock() @@ -1083,8 +1081,7 @@ class TestEnsureKnowledgeBase: provider._use_existing_knowledge_base = False provider.knowledge_base_name = "test-kb" provider.azure_openai_resource_url = "https://aoai.openai.azure.com" - provider.azure_openai_deployment_name = "deploy" - provider.model_name = "gpt-4" + provider.azure_openai_model = "gpt-4" provider.index_name = "test-index" provider.knowledge_base_output_mode = "answer_synthesis" @@ -1105,8 +1102,7 @@ class TestEnsureKnowledgeBase: provider._use_existing_knowledge_base = False provider.knowledge_base_name = "test-kb" provider.azure_openai_resource_url = "https://aoai.openai.azure.com" - provider.azure_openai_deployment_name = "deploy" - provider.model_name = "gpt-4" + provider.azure_openai_model = "gpt-4" provider.index_name = "test-index" provider.retrieval_reasoning_effort = "medium" diff --git a/python/packages/azure-ai/AGENTS.md b/python/packages/azure-ai/AGENTS.md index 6a89bec1da..b8244fd480 100644 --- a/python/packages/azure-ai/AGENTS.md +++ b/python/packages/azure-ai/AGENTS.md @@ -18,7 +18,7 @@ from agent_framework_azure_ai import AzureAIInferenceEmbeddingClient client = AzureAIInferenceEmbeddingClient( endpoint="https://.inference.ai.azure.com", api_key="...", - model_id="text-embedding-3-large", + model="text-embedding-3-large", ) result = await client.get_embeddings(["Hello"]) ``` diff --git a/python/packages/azure-ai/agent_framework_azure_ai/_embedding_client.py b/python/packages/azure-ai/agent_framework_azure_ai/_embedding_client.py index 3daa678333..ee8709d410 100644 --- a/python/packages/azure-ai/agent_framework_azure_ai/_embedding_client.py +++ b/python/packages/azure-ai/agent_framework_azure_ai/_embedding_client.py @@ -44,7 +44,7 @@ class AzureAIInferenceEmbeddingOptions(EmbeddingGenerationOptions, total=False): from agent_framework_azure_ai import AzureAIInferenceEmbeddingOptions options: AzureAIInferenceEmbeddingOptions = { - "model_id": "text-embedding-3-small", + "model": "text-embedding-3-small", "dimensions": 1536, "input_type": "document", "encoding_format": "float", @@ -54,8 +54,8 @@ class AzureAIInferenceEmbeddingOptions(EmbeddingGenerationOptions, total=False): input_type: str """Input type hint for the model. Common values: ``"text"``, ``"query"``, ``"document"``.""" - image_model_id: str - """Override model for image embeddings. Falls back to the client's ``image_model_id``.""" + image_model: str + """Override model for image embeddings. Falls back to the client's ``image_model``.""" encoding_format: str """Output encoding format. @@ -81,8 +81,8 @@ class AzureAIInferenceEmbeddingSettings(TypedDict, total=False): endpoint: str | None api_key: str | None - embedding_model_id: str | None - image_embedding_model_id: str | None + embedding_model: str | None + image_embedding_model: str | None class RawAzureAIInferenceEmbeddingClient( @@ -97,11 +97,11 @@ class RawAzureAIInferenceEmbeddingClient( are reassembled in the original input order. Keyword Args: - model_id: The text embedding model deployment name (e.g. "text-embedding-3-small"). - Can also be set via environment variable AZURE_AI_INFERENCE_EMBEDDING_MODEL_ID. - image_model_id: The image embedding model deployment name (e.g. "Cohere-embed-v3-english"). - Can also be set via environment variable AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID. - Falls back to ``model_id`` if not provided. + model: The text embedding model (e.g. "text-embedding-3-small"). + Can also be set via environment variable AZURE_AI_INFERENCE_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`` if not provided. endpoint: The Azure AI Inference endpoint URL. Can also be set via environment variable AZURE_AI_INFERENCE_ENDPOINT. api_key: API key for authentication. @@ -117,8 +117,8 @@ class RawAzureAIInferenceEmbeddingClient( def __init__( self, *, - model_id: str | None = None, - image_model_id: str | None = None, + model: str | None = None, + image_model: str | None = None, endpoint: str | None = None, api_key: str | None = None, text_client: EmbeddingsClient | None = None, @@ -132,17 +132,17 @@ class RawAzureAIInferenceEmbeddingClient( settings = load_settings( AzureAIInferenceEmbeddingSettings, env_prefix="AZURE_AI_INFERENCE_", - required_fields=["endpoint", "embedding_model_id"], + required_fields=["endpoint", "embedding_model"], endpoint=endpoint, api_key=api_key, - embedding_model_id=model_id, - image_embedding_model_id=image_model_id, + embedding_model=model, + image_embedding_model=image_model, env_file_path=env_file_path, env_file_encoding=env_file_encoding, ) - self.model_id = settings["embedding_model_id"] # type: ignore[reportTypedDictNotRequiredAccess] - self.image_model_id: str = settings.get("image_embedding_model_id") or self.model_id # type: ignore[assignment] + 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] if credential is None and settings.get("api_key"): @@ -202,7 +202,7 @@ class RawAzureAIInferenceEmbeddingClient( Generated embeddings with usage metadata. Raises: - ValueError: If model_id is not provided or an unsupported content type is encountered. + ValueError: If model is not provided or an unsupported content type is encountered. """ if not values: return GeneratedEmbeddings([], options=options) # type: ignore[reportReturnType] @@ -254,8 +254,8 @@ class RawAzureAIInferenceEmbeddingClient( # Embed text inputs. if text_items: - if not (text_model := opts.get("model_id") or self.model_id): - raise ValueError("An model_id is required, either in the client or options, for text inputs.") + if not (text_model := opts.get("model") or self.model): + raise ValueError("A model is required, either in the client or options, for text inputs.") text_inputs = [t for _, t in text_items] response = await self._text_client.embed( input=text_inputs, @@ -268,7 +268,7 @@ class RawAzureAIInferenceEmbeddingClient( embeddings[original_idx] = Embedding( vector=vector, dimensions=len(vector), - model_id=response.model or text_model, + model=response.model or text_model, ) if response.usage: usage_details["input_token_count"] = (usage_details.get("input_token_count") or 0) + ( @@ -280,8 +280,8 @@ class RawAzureAIInferenceEmbeddingClient( # Embed image inputs. if image_items: - if not (image_model := opts.get("image_model_id") or self.image_model_id): - raise ValueError("An image_model_id is required, either in the client or options, for image inputs.") + if not (image_model := opts.get("image_model") or self.image_model): + raise ValueError("An image_model is required, either in the client or options, for image inputs.") image_inputs = [img for _, img in image_items] response = await self._image_client.embed( input=image_inputs, @@ -294,7 +294,7 @@ class RawAzureAIInferenceEmbeddingClient( embeddings[original_idx] = Embedding( vector=image_vector, dimensions=len(image_vector), - model_id=response.model or image_model, + model=response.model or image_model, ) if response.usage: usage_details["input_token_count"] = (usage_details.get("input_token_count") or 0) + ( @@ -322,11 +322,11 @@ class AzureAIInferenceEmbeddingClient( ``Content.from_data()``. Keyword Args: - model_id: The text embedding model deployment name (e.g. "text-embedding-3-small"). - Can also be set via environment variable AZURE_AI_INFERENCE_EMBEDDING_MODEL_ID. - image_model_id: The image embedding model deployment name + model: The text embedding model (e.g. "text-embedding-3-small"). + Can also be set via environment variable AZURE_AI_INFERENCE_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_ID. Falls back to ``model_id``. + 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. api_key: API key for authentication. @@ -346,8 +346,8 @@ class AzureAIInferenceEmbeddingClient( # 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_ID=text-embedding-3-small - # Set AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID=Cohere-embed-v3-english + # Set AZURE_AI_INFERENCE_EMBEDDING_MODEL=text-embedding-3-small + # Set AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL=Cohere-embed-v3-english client = AzureAIInferenceEmbeddingClient() # Text embeddings @@ -368,8 +368,8 @@ class AzureAIInferenceEmbeddingClient( def __init__( self, *, - model_id: str | None = None, - image_model_id: str | None = None, + model: str | None = None, + image_model: str | None = None, endpoint: str | None = None, api_key: str | None = None, text_client: EmbeddingsClient | None = None, @@ -382,8 +382,8 @@ class AzureAIInferenceEmbeddingClient( ) -> None: """Initialize an Azure AI Inference embedding client.""" super().__init__( - model_id=model_id, - image_model_id=image_model_id, + model=model, + image_model=image_model, endpoint=endpoint, api_key=api_key, text_client=text_client, diff --git a/python/packages/azure-ai/agent_framework_azure_ai/_shared.py b/python/packages/azure-ai/agent_framework_azure_ai/_shared.py index 66b92a9fd6..ce167a1f82 100644 --- a/python/packages/azure-ai/agent_framework_azure_ai/_shared.py +++ b/python/packages/azure-ai/agent_framework_azure_ai/_shared.py @@ -20,8 +20,8 @@ class AzureAISettings(TypedDict, total=False): Keyword Args: project_endpoint: The Azure AI Project endpoint URL. Can be set via environment variable AZURE_AI_PROJECT_ENDPOINT. - model_deployment_name: The name of the model deployment to use. - Can be set via environment variable AZURE_AI_MODEL_DEPLOYMENT_NAME. + 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'. @@ -32,12 +32,12 @@ class AzureAISettings(TypedDict, total=False): # Using environment variables # Set AZURE_AI_PROJECT_ENDPOINT=https://your-project.cognitiveservices.azure.com - # Set AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4 + # Set AZURE_AI_MODEL=gpt-4 settings = AzureAISettings() # Or passing parameters directly settings = AzureAISettings( - project_endpoint="https://your-project.cognitiveservices.azure.com", model_deployment_name="gpt-4" + project_endpoint="https://your-project.cognitiveservices.azure.com", model="gpt-4" ) # Or loading from a .env file @@ -45,4 +45,4 @@ class AzureAISettings(TypedDict, total=False): """ project_endpoint: str | None - model_deployment_name: str | None + model: str | None diff --git a/python/packages/azure-ai/tests/azure_ai/test_azure_ai_inference_embedding_client.py b/python/packages/azure-ai/tests/azure_ai/test_azure_ai_inference_embedding_client.py index 0ec6a8b811..812c2eaf29 100644 --- a/python/packages/azure-ai/tests/azure_ai/test_azure_ai_inference_embedding_client.py +++ b/python/packages/azure-ai/tests/azure_ai/test_azure_ai_inference_embedding_client.py @@ -60,7 +60,7 @@ def mock_image_client() -> AsyncMock: def raw_client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> RawAzureAIInferenceEmbeddingClient[Any]: """Create a RawAzureAIInferenceEmbeddingClient with mocked SDK clients.""" return RawAzureAIInferenceEmbeddingClient( - model_id="test-model", + model="test-model", endpoint="https://test.inference.ai.azure.com", api_key="test-key", text_client=mock_text_client, @@ -72,7 +72,7 @@ def raw_client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> Raw def client(mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> AzureAIInferenceEmbeddingClient[Any]: """Create an AzureAIInferenceEmbeddingClient with mocked SDK clients.""" return AzureAIInferenceEmbeddingClient( - model_id="test-model", + model="test-model", endpoint="https://test.inference.ai.azure.com", api_key="test-key", text_client=mock_text_client, @@ -162,8 +162,8 @@ class TestRawAzureAIInferenceEmbeddingClient: async def test_model_override_in_options( self, raw_client: RawAzureAIInferenceEmbeddingClient[Any], mock_text_client: AsyncMock ) -> None: - """model_id in options overrides the default.""" - options: AzureAIInferenceEmbeddingOptions = {"model_id": "custom-model"} + """model in options overrides the default.""" + options: AzureAIInferenceEmbeddingOptions = {"model": "custom-model"} await raw_client.get_embeddings(["hello"], options=options) call_kwargs = mock_text_client.embed.call_args @@ -196,55 +196,55 @@ class TestRawAzureAIInferenceEmbeddingClient: { "AZURE_AI_INFERENCE_ENDPOINT": "https://env.inference.ai.azure.com", "AZURE_AI_INFERENCE_API_KEY": "env-key", - "AZURE_AI_INFERENCE_EMBEDDING_MODEL_ID": "env-model", + "AZURE_AI_INFERENCE_EMBEDDING_MODEL": "env-model", }, ), patch("agent_framework_azure_ai._embedding_client.EmbeddingsClient"), patch("agent_framework_azure_ai._embedding_client.ImageEmbeddingsClient"), ): client = RawAzureAIInferenceEmbeddingClient() - assert client.model_id == "env-model" - assert client.image_model_id == "env-model" # falls back to model_id + assert client.model == "env-model" + assert client.image_model == "env-model" # falls back to model - def test_image_model_id_from_env(self) -> None: - """image_model_id is loaded from its own environment variable.""" + def test_image_model_from_env(self) -> None: + """image_model is loaded from its own environment variable.""" with ( 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_ID": "text-model", - "AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID": "image-model", + "AZURE_AI_INFERENCE_EMBEDDING_MODEL": "text-model", + "AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL": "image-model", }, ), patch("agent_framework_azure_ai._embedding_client.EmbeddingsClient"), patch("agent_framework_azure_ai._embedding_client.ImageEmbeddingsClient"), ): client = RawAzureAIInferenceEmbeddingClient() - assert client.model_id == "text-model" - assert client.image_model_id == "image-model" + assert client.model == "text-model" + assert client.image_model == "image-model" - def test_image_model_id_explicit(self, mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> None: - """image_model_id can be set explicitly.""" + def test_image_model_explicit(self, mock_text_client: AsyncMock, mock_image_client: AsyncMock) -> None: + """image_model can be set explicitly.""" client = RawAzureAIInferenceEmbeddingClient( - model_id="text-model", - image_model_id="image-model", + model="text-model", + image_model="image-model", endpoint="https://test.inference.ai.azure.com", api_key="test-key", text_client=mock_text_client, image_client=mock_image_client, ) - assert client.model_id == "text-model" - assert client.image_model_id == "image-model" + assert client.model == "text-model" + assert client.image_model == "image-model" - async def test_image_model_id_sent_to_image_client( + async def test_image_model_sent_to_image_client( self, mock_text_client: AsyncMock, mock_image_client: AsyncMock ) -> None: - """image_model_id is passed to the image client embed call.""" + """image_model is passed to the image client embed call.""" client = RawAzureAIInferenceEmbeddingClient( - model_id="text-model", - image_model_id="image-model", + model="text-model", + image_model="image-model", endpoint="https://test.inference.ai.azure.com", api_key="test-key", text_client=mock_text_client, @@ -274,7 +274,7 @@ class TestAzureAIInferenceEmbeddingClient: 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( - model_id="test-model", + model="test-model", endpoint="https://test.inference.ai.azure.com", api_key="test-key", text_client=mock_text_client, @@ -291,7 +291,7 @@ def _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_ID") + and os.environ.get("AZURE_AI_INFERENCE_EMBEDDING_MODEL") ) @@ -313,4 +313,4 @@ class TestAzureAIInferenceEmbeddingIntegration: result = await client.get_embeddings(["Hello, world!"]) assert len(result) == 1 assert len(result[0].vector) > 0 - assert result[0].model_id is not None + assert result[0].model is not None diff --git a/python/packages/azure-ai/tests/conftest.py b/python/packages/azure-ai/tests/conftest.py index 3f635e8213..62c09226c4 100644 --- a/python/packages/azure-ai/tests/conftest.py +++ b/python/packages/azure-ai/tests/conftest.py @@ -29,7 +29,7 @@ def azure_ai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): env_vars = { "AZURE_AI_PROJECT_ENDPOINT": "https://test-project.cognitiveservices.azure.com/", - "AZURE_AI_MODEL_DEPLOYMENT_NAME": "test-gpt-4o", + "AZURE_AI_MODEL": "test-gpt-4o", } env_vars.update(override_env_param_dict) # type: ignore diff --git a/python/packages/azure-cosmos/samples/cosmos_history_provider.py b/python/packages/azure-cosmos/samples/cosmos_history_provider.py index 8dd38a7cdc..67235cbf14 100644 --- a/python/packages/azure-cosmos/samples/cosmos_history_provider.py +++ b/python/packages/azure-cosmos/samples/cosmos_history_provider.py @@ -35,7 +35,7 @@ Optional: async def main() -> None: """Run the Cosmos history provider sample with an Agent.""" project_endpoint = os.getenv("FOUNDRY_PROJECT_ENDPOINT") - deployment_name = os.getenv("FOUNDRY_MODEL") + model = os.getenv("FOUNDRY_MODEL") cosmos_endpoint = os.getenv("AZURE_COSMOS_ENDPOINT") cosmos_database_name = os.getenv("AZURE_COSMOS_DATABASE_NAME") cosmos_container_name = os.getenv("AZURE_COSMOS_CONTAINER_NAME") @@ -43,7 +43,7 @@ async def main() -> None: if ( not project_endpoint - or not deployment_name + or not model or not cosmos_endpoint or not cosmos_database_name or not cosmos_container_name @@ -58,7 +58,7 @@ async def main() -> None: async with AzureCliCredential() as credential: client = FoundryChatClient( project_endpoint=project_endpoint, - model=deployment_name, + model=model, credential=credential, ) diff --git a/python/packages/azurefunctions/tests/integration_tests/.env.example b/python/packages/azurefunctions/tests/integration_tests/.env.example index e956fe48e6..75baa4aa27 100644 --- a/python/packages/azurefunctions/tests/integration_tests/.env.example +++ b/python/packages/azurefunctions/tests/integration_tests/.env.example @@ -1,6 +1,6 @@ # Azure OpenAI Configuration AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=your-deployment-name +AZURE_OPENAI_MODEL=your-deployment-name FUNCTIONS_WORKER_RUNTIME=python # Azure Functions Configuration diff --git a/python/packages/azurefunctions/tests/integration_tests/README.md b/python/packages/azurefunctions/tests/integration_tests/README.md index 8b1f05f6b0..291d7347f3 100644 --- a/python/packages/azurefunctions/tests/integration_tests/README.md +++ b/python/packages/azurefunctions/tests/integration_tests/README.md @@ -14,7 +14,7 @@ cp .env.example .env Required variables: - `AZURE_OPENAI_ENDPOINT` -- `AZURE_OPENAI_DEPLOYMENT_NAME` +- `AZURE_OPENAI_MODEL` - `AZURE_OPENAI_API_KEY` - `AzureWebJobsStorage` - `DURABLE_TASK_SCHEDULER_CONNECTION_STRING` diff --git a/python/packages/azurefunctions/tests/integration_tests/conftest.py b/python/packages/azurefunctions/tests/integration_tests/conftest.py index 98ce922f7e..4f180d4921 100644 --- a/python/packages/azurefunctions/tests/integration_tests/conftest.py +++ b/python/packages/azurefunctions/tests/integration_tests/conftest.py @@ -115,7 +115,7 @@ def _should_skip_azure_functions_integration_tests() -> tuple[bool, str]: os.getenv("FOUNDRY_MODEL", "").strip() ) has_azure_openai_config = bool(os.getenv("AZURE_OPENAI_ENDPOINT", "").strip()) and bool( - os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "").strip() + os.getenv("AZURE_OPENAI_MODEL", "").strip() ) if not has_foundry_config and not has_azure_openai_config: return ( @@ -339,7 +339,7 @@ def _load_and_validate_env(sample_path: Path) -> None: "FUNCTIONS_WORKER_RUNTIME", ] if sample_path.name == "11_workflow_parallel": - required_env_vars.extend(["AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_DEPLOYMENT_NAME"]) + required_env_vars.extend(["AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_MODEL"]) else: required_env_vars.extend(["FOUNDRY_PROJECT_ENDPOINT", "FOUNDRY_MODEL"]) diff --git a/python/packages/bedrock/AGENTS.md b/python/packages/bedrock/AGENTS.md index 0ab072ed24..00245229f5 100644 --- a/python/packages/bedrock/AGENTS.md +++ b/python/packages/bedrock/AGENTS.md @@ -14,7 +14,7 @@ Integration with AWS Bedrock for LLM inference. ```python from agent_framework.amazon import BedrockChatClient -client = BedrockChatClient(model_id="anthropic.claude-3-sonnet-20240229-v1:0") +client = BedrockChatClient(model="anthropic.claude-3-sonnet-20240229-v1:0") response = await client.get_response("Hello") ``` diff --git a/python/packages/bedrock/agent_framework_bedrock/_chat_client.py b/python/packages/bedrock/agent_framework_bedrock/_chat_client.py index 0aefbe12f3..3606cdf26b 100644 --- a/python/packages/bedrock/agent_framework_bedrock/_chat_client.py +++ b/python/packages/bedrock/agent_framework_bedrock/_chat_client.py @@ -101,7 +101,7 @@ class BedrockChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], t Keys: # Inherited from ChatOptions (mapped to Bedrock): - model_id: The Bedrock model identifier, + model: The Bedrock model identifier, translates to ``modelId`` in Bedrock API. temperature: Sampling temperature, translates to ``inferenceConfig.temperature``. @@ -175,7 +175,7 @@ class BedrockChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], t BEDROCK_OPTION_TRANSLATIONS: dict[str, str] = { - "model_id": "modelId", + "model": "modelId", "max_tokens": "maxTokens", "top_p": "topP", "stop": "stopSequences", @@ -209,7 +209,7 @@ class BedrockSettings(TypedDict, total=False): """Bedrock configuration settings pulled from environment variables or .env files.""" region: str | None - chat_model_id: str | None + chat_model: str | None access_key: SecretString | None secret_key: SecretString | None session_token: SecretString | None @@ -230,7 +230,7 @@ class BedrockChatClient( self, *, region: str | None = None, - model_id: str | None = None, + model: str | None = None, access_key: str | None = None, secret_key: str | None = None, session_token: str | None = None, @@ -246,7 +246,7 @@ class BedrockChatClient( Args: region: Region to send Bedrock requests to; falls back to BEDROCK_REGION. - model_id: Default model identifier; falls back to BEDROCK_CHAT_MODEL_ID. + model: Default model identifier; falls back to BEDROCK_CHAT_MODEL. access_key: Optional AWS access key for manual credential injection. secret_key: Optional AWS secret key paired with ``access_key``. session_token: Optional AWS session token for temporary credentials. @@ -264,7 +264,7 @@ class BedrockChatClient( from agent_framework.amazon import BedrockChatClient # Basic usage with default credentials - client = BedrockChatClient(model_id="") + client = BedrockChatClient(model="") # Using custom ChatOptions with type safety: from typing import TypedDict @@ -275,14 +275,14 @@ class BedrockChatClient( my_custom_option: str - client = BedrockChatClient[MyOptions](model_id="") + client = BedrockChatClient[MyOptions](model="") response = await client.get_response("Hello", options={"my_custom_option": "value"}) """ settings = load_settings( BedrockSettings, env_prefix="BEDROCK_", region=region, - chat_model_id=model_id, + chat_model=model, access_key=access_key, secret_key=secret_key, session_token=session_token, @@ -290,7 +290,7 @@ class BedrockChatClient( env_file_encoding=env_file_encoding, ) region = settings.get("region") or DEFAULT_REGION - chat_model_id = settings.get("chat_model_id") + chat_model = settings.get("chat_model") if client: self._bedrock_client = client @@ -307,7 +307,7 @@ class BedrockChatClient( middleware=middleware, function_invocation_configuration=function_invocation_configuration, ) - self.model_id = chat_model_id + self.model = chat_model self.region = region @staticmethod @@ -355,7 +355,7 @@ class BedrockChatClient( yield ChatResponseUpdate( response_id=parsed_response.response_id, contents=contents, - model_id=parsed_response.model_id, + model=parsed_response.model, finish_reason=finish_reason, raw_representation=parsed_response.raw_representation, ) @@ -375,10 +375,10 @@ class BedrockChatClient( options: Mapping[str, Any], **kwargs: Any, ) -> dict[str, Any]: - model_id = options.get("model_id") or self.model_id - if not model_id: + model = options.get("model") or self.model + if not model: raise ValueError( - "Bedrock model_id is required. Set via chat options or BEDROCK_CHAT_MODEL_ID environment variable." + "Bedrock model is required. Set via chat options or BEDROCK_CHAT_MODEL environment variable." ) system_prompts, conversation = self._prepare_bedrock_messages(messages) @@ -389,7 +389,7 @@ class BedrockChatClient( system_prompts = [{"text": instructions}, *system_prompts] run_options: dict[str, Any] = { - "modelId": model_id, + "modelId": model, "messages": conversation, "inferenceConfig": {"maxTokens": options.get("max_tokens", DEFAULT_MAX_TOKENS)}, } @@ -633,12 +633,12 @@ class BedrockChatClient( usage_details = self._parse_usage(usage_source) finish_reason = self._map_finish_reason(output.get("completionReason") or response.get("stopReason")) response_id = response.get("responseId") or message.get("id") - model_id = response.get("modelId") or output.get("modelId") or self.model_id + model = response.get("modelId") or output.get("modelId") or self.model return ChatResponse( response_id=response_id, messages=[chat_message], usage_details=usage_details, - model_id=model_id, + model=model, finish_reason=finish_reason, raw_representation=response, ) diff --git a/python/packages/bedrock/agent_framework_bedrock/_embedding_client.py b/python/packages/bedrock/agent_framework_bedrock/_embedding_client.py index 3161ed4c88..99250b8248 100644 --- a/python/packages/bedrock/agent_framework_bedrock/_embedding_client.py +++ b/python/packages/bedrock/agent_framework_bedrock/_embedding_client.py @@ -39,7 +39,7 @@ class BedrockEmbeddingSettings(TypedDict, total=False): """Bedrock embedding settings.""" region: str | None - embedding_model_id: str | None + embedding_model: str | None access_key: SecretString | None secret_key: SecretString | None session_token: SecretString | None @@ -56,7 +56,7 @@ class BedrockEmbeddingOptions(EmbeddingGenerationOptions, total=False): from agent_framework_bedrock import BedrockEmbeddingOptions options: BedrockEmbeddingOptions = { - "model_id": "amazon.titan-embed-text-v2:0", + "model": "amazon.titan-embed-text-v2:0", "dimensions": 1024, "normalize": True, } @@ -80,8 +80,8 @@ class RawBedrockEmbeddingClient( """Raw Bedrock embedding client without telemetry. Keyword Args: - model_id: The Bedrock embedding model ID (e.g. "amazon.titan-embed-text-v2:0"). - Can also be set via environment variable BEDROCK_EMBEDDING_MODEL_ID. + model: The Bedrock embedding model ID (e.g. "amazon.titan-embed-text-v2:0"). + Can also be set via environment variable BEDROCK_EMBEDDING_MODEL. region: AWS region. Will try to load from BEDROCK_REGION env var, if not set, the regular Boto3 configuration/loading applies (which may include other env vars, config files, or instance metadata). @@ -98,7 +98,7 @@ class RawBedrockEmbeddingClient( self, *, region: str | None = None, - model_id: str | None = None, + model: str | None = None, access_key: str | None = None, secret_key: str | None = None, session_token: str | None = None, @@ -112,9 +112,9 @@ class RawBedrockEmbeddingClient( settings = load_settings( BedrockEmbeddingSettings, env_prefix="BEDROCK_", - required_fields=["embedding_model_id"], + required_fields=["embedding_model"], region=region, - embedding_model_id=model_id, + embedding_model=model, access_key=access_key, secret_key=secret_key, session_token=session_token, @@ -143,7 +143,7 @@ class RawBedrockEmbeddingClient( config=BotoConfig(user_agent_extra=AGENT_FRAMEWORK_USER_AGENT), ) - self.model_id: str = settings["embedding_model_id"] # type: ignore[assignment] # pyright: ignore[reportTypedDictNotRequiredAccess] + self.model: str = settings["embedding_model"] # type: ignore[assignment] # pyright: ignore[reportTypedDictNotRequiredAccess] self.region = resolved_region super().__init__(additional_properties=additional_properties) @@ -170,15 +170,15 @@ class RawBedrockEmbeddingClient( Generated embeddings with usage metadata. Raises: - ValueError: If model_id is not provided or values is empty. + ValueError: If model is not provided or values is empty. """ if not values: return GeneratedEmbeddings([], options=options) opts: dict[str, Any] = dict(options) if options else {} - model = opts.get("model_id") or self.model_id + model = opts.get("model") or self.model if not model: - raise ValueError("model_id is required") + raise ValueError("model is required") embedding_results = await asyncio.gather( *(self._generate_embedding_for_text(opts, model, text) for text in values) @@ -218,7 +218,7 @@ class RawBedrockEmbeddingClient( embedding = Embedding( vector=response_body["embedding"], dimensions=len(response_body["embedding"]), - model_id=model, + model=model, ) input_tokens = int(response_body.get("inputTextTokenCount", 0)) return embedding, input_tokens @@ -234,8 +234,8 @@ class BedrockEmbeddingClient( Uses the Amazon Titan Embeddings model via Bedrock's invoke_model API. Keyword Args: - model_id: The Bedrock embedding model ID (e.g. "amazon.titan-embed-text-v2:0"). - Can also be set via environment variable BEDROCK_EMBEDDING_MODEL_ID. + model: The Bedrock embedding model ID (e.g. "amazon.titan-embed-text-v2:0"). + Can also be set via environment variable BEDROCK_EMBEDDING_MODEL. region: AWS region. Defaults to "us-east-1". Can also be set via environment variable BEDROCK_REGION. access_key: AWS access key for manual credential injection. @@ -253,7 +253,7 @@ class BedrockEmbeddingClient( # Using default AWS credentials client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", ) # Generate embeddings @@ -267,7 +267,7 @@ class BedrockEmbeddingClient( self, *, region: str | None = None, - model_id: str | None = None, + model: str | None = None, access_key: str | None = None, secret_key: str | None = None, session_token: str | None = None, @@ -281,7 +281,7 @@ class BedrockEmbeddingClient( """Initialize a Bedrock embedding client.""" super().__init__( region=region, - model_id=model_id, + model=model, access_key=access_key, secret_key=secret_key, session_token=session_token, diff --git a/python/packages/bedrock/tests/bedrock/test_bedrock_embedding_client.py b/python/packages/bedrock/tests/bedrock/test_bedrock_embedding_client.py index f6f96254a7..afb32c4158 100644 --- a/python/packages/bedrock/tests/bedrock/test_bedrock_embedding_client.py +++ b/python/packages/bedrock/tests/bedrock/test_bedrock_embedding_client.py @@ -39,17 +39,17 @@ async def test_bedrock_embedding_construction() -> None: """Test construction with explicit parameters.""" stub = _StubBedrockEmbeddingRuntime() client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", region="us-west-2", client=stub, ) - assert client.model_id == "amazon.titan-embed-text-v2:0" + assert client.model == "amazon.titan-embed-text-v2:0" assert client.region == "us-west-2" async def test_bedrock_embedding_construction_missing_model_raises(monkeypatch: pytest.MonkeyPatch) -> None: - """Test that missing model_id raises an error.""" - monkeypatch.delenv("BEDROCK_EMBEDDING_MODEL_ID", raising=False) + """Test that missing model raises an error.""" + monkeypatch.delenv("BEDROCK_EMBEDDING_MODEL", raising=False) from agent_framework.exceptions import SettingNotFoundError with pytest.raises(SettingNotFoundError): @@ -60,7 +60,7 @@ async def test_bedrock_embedding_get_embeddings() -> None: """Test generating embeddings via the Bedrock invoke_model API.""" stub = _StubBedrockEmbeddingRuntime() client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", region="us-west-2", client=stub, ) @@ -71,7 +71,7 @@ async def test_bedrock_embedding_get_embeddings() -> None: assert len(result) == 2 assert len(result[0].vector) == 3 assert len(result[1].vector) == 3 - assert result[0].model_id == "amazon.titan-embed-text-v2:0" + assert result[0].model == "amazon.titan-embed-text-v2:0" assert result.usage == {"input_token_count": 10} # Two calls since Titan processes one input at a time @@ -84,7 +84,7 @@ async def test_bedrock_embedding_get_embeddings_empty_input() -> None: """Test generating embeddings with empty input.""" stub = _StubBedrockEmbeddingRuntime() client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", region="us-west-2", client=stub, ) @@ -100,7 +100,7 @@ async def test_bedrock_embedding_get_embeddings_with_options() -> None: """Test generating embeddings with custom options.""" stub = _StubBedrockEmbeddingRuntime() client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", region="us-west-2", client=stub, ) @@ -120,16 +120,16 @@ async def test_bedrock_embedding_get_embeddings_with_options() -> None: async def test_bedrock_embedding_get_embeddings_no_model_raises() -> None: - """Test that missing model_id at call time raises ValueError.""" + """Test that missing model at call time raises ValueError.""" stub = _StubBedrockEmbeddingRuntime() client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", region="us-west-2", client=stub, ) - client.model_id = None # type: ignore[assignment] + client.model = None # type: ignore[assignment] - with pytest.raises(ValueError, match="model_id is required"): + with pytest.raises(ValueError, match="model is required"): await client.get_embeddings(["hello"]) @@ -137,7 +137,7 @@ async def test_bedrock_embedding_default_region() -> None: """Test that default region is us-east-1.""" stub = _StubBedrockEmbeddingRuntime() client = BedrockEmbeddingClient( - model_id="amazon.titan-embed-text-v2:0", + model="amazon.titan-embed-text-v2:0", client=stub, ) assert client.region == "us-east-1" @@ -146,7 +146,7 @@ async def test_bedrock_embedding_default_region() -> None: # region: Integration Tests skip_if_bedrock_embedding_integration_tests_disabled = pytest.mark.skipif( - os.getenv("BEDROCK_EMBEDDING_MODEL_ID", "") in ("", "test-model") + os.getenv("BEDROCK_EMBEDDING_MODEL", "") in ("", "test-model") or not (os.getenv("AWS_ACCESS_KEY_ID") or os.getenv("BEDROCK_ACCESS_KEY")), reason="No real Bedrock embedding model or AWS credentials provided; skipping integration tests.", ) diff --git a/python/packages/bedrock/tests/test_bedrock_client.py b/python/packages/bedrock/tests/test_bedrock_client.py index 1566bff234..fbc241b24c 100644 --- a/python/packages/bedrock/tests/test_bedrock_client.py +++ b/python/packages/bedrock/tests/test_bedrock_client.py @@ -34,7 +34,7 @@ class _StubBedrockRuntime: def _make_client() -> BedrockChatClient: """Create a BedrockChatClient with a stub runtime for unit tests.""" return BedrockChatClient( - model_id="amazon.titan-text", + model="amazon.titan-text", region="us-west-2", client=_StubBedrockRuntime(), ) @@ -43,7 +43,7 @@ def _make_client() -> BedrockChatClient: async def test_get_response_invokes_bedrock_runtime() -> None: stub = _StubBedrockRuntime() client = BedrockChatClient( - model_id="amazon.titan-text", + model="amazon.titan-text", region="us-west-2", client=stub, ) @@ -65,7 +65,7 @@ async def test_get_response_invokes_bedrock_runtime() -> None: def test_build_request_requires_non_system_messages() -> None: client = BedrockChatClient( - model_id="amazon.titan-text", + model="amazon.titan-text", region="us-west-2", client=_StubBedrockRuntime(), ) diff --git a/python/packages/bedrock/tests/test_bedrock_settings.py b/python/packages/bedrock/tests/test_bedrock_settings.py index 85e417602a..c828c2dc94 100644 --- a/python/packages/bedrock/tests/test_bedrock_settings.py +++ b/python/packages/bedrock/tests/test_bedrock_settings.py @@ -24,7 +24,7 @@ class _WeatherArgs(BaseModel): def _build_client() -> BedrockChatClient: fake_runtime = MagicMock() fake_runtime.converse.return_value = {} - return BedrockChatClient(model_id="test-model", client=fake_runtime) + return BedrockChatClient(model="test-model", client=fake_runtime) def _dummy_weather(location: str) -> str: # pragma: no cover - helper @@ -33,10 +33,10 @@ def _dummy_weather(location: str) -> str: # pragma: no cover - helper def test_settings_load_from_environment(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("BEDROCK_REGION", "us-west-2") - monkeypatch.setenv("BEDROCK_CHAT_MODEL_ID", "anthropic.claude-v2") + monkeypatch.setenv("BEDROCK_CHAT_MODEL", "anthropic.claude-v2") settings = load_settings(BedrockSettings, env_prefix="BEDROCK_") assert settings["region"] == "us-west-2" - assert settings["chat_model_id"] == "anthropic.claude-v2" + assert settings["chat_model"] == "anthropic.claude-v2" def test_build_request_includes_tool_config() -> None: diff --git a/python/packages/core/README.md b/python/packages/core/README.md index cb03025db5..d817b3b3be 100644 --- a/python/packages/core/README.md +++ b/python/packages/core/README.md @@ -39,7 +39,7 @@ OPENAI_RESPONSES_MODEL=... ... AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=... -AZURE_OPENAI_DEPLOYMENT_NAME=... +AZURE_OPENAI_MODEL=... ``` You can also override environment variables by explicitly passing configuration parameters to the chat client constructor: diff --git a/python/packages/core/agent_framework/_agents.py b/python/packages/core/agent_framework/_agents.py index b857a6377f..6f1be6c323 100644 --- a/python/packages/core/agent_framework/_agents.py +++ b/python/packages/core/agent_framework/_agents.py @@ -100,6 +100,7 @@ def _merge_options(base: dict[str, Any], override: dict[str, Any]) -> dict[str, A new merged options dict. """ result = dict(base) + for key, value in override.items(): if value is None: continue @@ -596,7 +597,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] from agent_framework.openai import OpenAIChatClient # Create a basic chat agent - client = OpenAIChatClient(model_id="gpt-4") + client = OpenAIChatClient(model="gpt-4") agent = Agent(client=client, name="assistant", description="A helpful assistant") # Run the agent with a simple message @@ -634,7 +635,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] from agent_framework import Agent from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions - client = OpenAIChatClient(model_id="gpt-4o") + client = OpenAIChatClient(model="gpt-4o") agent: Agent[OpenAIChatOptions] = Agent( client=client, name="reasoning-agent", @@ -692,7 +693,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] service-managed conversation instead. default_options: A TypedDict containing chat options. When using a typed agent like ``Agent[OpenAIChatOptions]``, this enables IDE autocomplete for - provider-specific options including temperature, max_tokens, model_id, + provider-specific options including temperature, max_tokens, model, tool_choice, and provider-specific options like reasoning_effort. You can also create your own TypedDict for custom chat clients. Note: response_format typing does not flow into run outputs when set via default_options. @@ -736,9 +737,10 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] self.mcp_tools: list[MCPTool] = [tool for tool in normalized_tools if isinstance(tool, MCPTool)] agent_tools = [tool for tool in normalized_tools if not isinstance(tool, MCPTool)] + model = opts.pop("model", None) or getattr(self.client, "model", None) + # Build chat options dict self.default_options: dict[str, Any] = { - "model_id": opts.pop("model_id", None) or (getattr(self.client, "model_id", None)), "allow_multiple_tool_calls": opts.pop("allow_multiple_tool_calls", None), "conversation_id": opts.pop("conversation_id", None), "frequency_penalty": opts.pop("frequency_penalty", None), @@ -758,6 +760,8 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] "user": opts.pop("user", None), **opts, # Remaining options are provider-specific } + if model is not None: + self.default_options["model"] = model # Remove None values from chat_options self.default_options = {k: v for k, v in self.default_options.items() if v is not None} self._async_exit_stack = AsyncExitStack() @@ -914,7 +918,7 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] tools: The tools to use for this specific run (merged with default tools). options: A TypedDict containing chat options. When using a typed agent like ``Agent[OpenAIChatOptions]``, this enables IDE autocomplete for - provider-specific options including temperature, max_tokens, model_id, + provider-specific options including temperature, max_tokens, model, tool_choice, and provider-specific options like reasoning_effort. compaction_strategy: Optional per-run compaction override passed to ``client.get_response()``. When omitted, the agent-level override @@ -1243,9 +1247,10 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] ) additional_function_arguments = {**effective_function_invocation_kwargs, **existing_additional_args} + model = opts.pop("model", None) + # Build options dict from run() options merged with provided options run_opts: dict[str, Any] = { - "model_id": opts.pop("model_id", None), "conversation_id": active_session.service_session_id if active_session else opts.pop("conversation_id", None), @@ -1266,6 +1271,8 @@ class RawAgent(BaseAgent, Generic[OptionsCoT]): # type: ignore[misc] "user": opts.pop("user", None), **opts, # Remaining options are provider-specific } + if model is not None: + run_opts["model"] = model # Remove None values and merge with chat_options run_opts = {k: v for k, v in run_opts.items() if v is not None} co = _merge_options(chat_options, run_opts) diff --git a/python/packages/core/agent_framework/_clients.py b/python/packages/core/agent_framework/_clients.py index 41bcf25883..cd810f8675 100644 --- a/python/packages/core/agent_framework/_clients.py +++ b/python/packages/core/agent_framework/_clients.py @@ -592,7 +592,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]): tools: The tools to use for the request. default_options: A TypedDict containing chat options. When using a typed client like ``OpenAIChatClient``, this enables IDE autocomplete for provider-specific options - including temperature, max_tokens, model_id, tool_choice, and more. + including temperature, max_tokens, model, tool_choice, and more. Note: response_format typing does not flow into run outputs when set via default_options, and dict literals are accepted without specialized option typing. context_providers: Context providers to include during agent invocation. @@ -617,7 +617,7 @@ class BaseChatClient(SerializationMixin, ABC, Generic[OptionsCoT]): from agent_framework.openai import OpenAIChatClient # Create a client - client = OpenAIChatClient(model_id="gpt-4") + client = OpenAIChatClient(model="gpt-4") # Create an agent using the convenience method agent = client.as_agent( diff --git a/python/packages/core/agent_framework/_mcp.py b/python/packages/core/agent_framework/_mcp.py index e40bb46f00..9dfb29932f 100644 --- a/python/packages/core/agent_framework/_mcp.py +++ b/python/packages/core/agent_framework/_mcp.py @@ -819,7 +819,7 @@ class MCPTool: return types.CreateMessageResult( role="assistant", content=mcp_content, - model=response.model_id or "unknown", + model=response.model or "unknown", ) async def logging_callback(self, params: types.LoggingMessageNotificationParams) -> None: diff --git a/python/packages/core/agent_framework/_middleware.py b/python/packages/core/agent_framework/_middleware.py index 31950e0d7b..eb87ba1946 100644 --- a/python/packages/core/agent_framework/_middleware.py +++ b/python/packages/core/agent_framework/_middleware.py @@ -294,7 +294,7 @@ class ChatContext: async def process(self, context: ChatContext, call_next): print(f"Chat client: {context.chat_client.__class__.__name__}") print(f"Messages: {len(context.messages)}") - print(f"Model: {context.options.get('model_id')}") + print(f"Model: {context.options.get('model')}") # Store metadata context.metadata["input_tokens"] = self.count_tokens(context.messages) diff --git a/python/packages/core/agent_framework/_serialization.py b/python/packages/core/agent_framework/_serialization.py index 30c5b80fa1..3313bf04a7 100644 --- a/python/packages/core/agent_framework/_serialization.py +++ b/python/packages/core/agent_framework/_serialization.py @@ -431,7 +431,7 @@ class SerializationMixin: # Serialized data contains only the model configuration client_data = { "type": "open_ai_chat_client", - "model_id": "gpt-4o-mini", + "model": "gpt-4o-mini", # client is excluded from serialization } diff --git a/python/packages/core/agent_framework/_settings.py b/python/packages/core/agent_framework/_settings.py index 4eecf3434d..9f9ab29a39 100644 --- a/python/packages/core/agent_framework/_settings.py +++ b/python/packages/core/agent_framework/_settings.py @@ -11,21 +11,21 @@ Usage:: class MySettings(TypedDict, total=False): api_key: str | None # optional — resolves to None if not set - model_id: str | None # optional by default + model: str | None # optional by default source_a: str | None source_b: str | None - # Make model_id required; require exactly one of source_a / source_b: + # Make model required; require exactly one of source_a / source_b: settings = load_settings( MySettings, env_prefix="MY_APP_", - required_fields=["model_id", ("source_a", "source_b")], - model_id="gpt-4", + required_fields=["model", ("source_a", "source_b")], + model="gpt-4", source_a="value", ) settings["api_key"] # type-checked dict access - settings["model_id"] # str | None per type, but guaranteed not None at runtime + settings["model"] # str | None per type, but guaranteed not None at runtime """ from __future__ import annotations diff --git a/python/packages/core/agent_framework/_types.py b/python/packages/core/agent_framework/_types.py index bd468b8450..ccad977f21 100644 --- a/python/packages/core/agent_framework/_types.py +++ b/python/packages/core/agent_framework/_types.py @@ -1872,8 +1872,8 @@ def _process_update(response: ChatResponse | AgentResponse, update: ChatResponse response.conversation_id = update.conversation_id if update.finish_reason is not None: response.finish_reason = update.finish_reason - if update.model_id is not None: - response.model_id = update.model_id + if update.model is not None: + response.model = update.model response.continuation_token = update.continuation_token @@ -1956,7 +1956,7 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): messages: The list of chat messages in the response. response_id: The ID of the chat response. conversation_id: An identifier for the state of the conversation. - model_id: The model ID used in the creation of the chat response. + model: The model used in the creation of the chat response. created_at: A timestamp for the chat response. finish_reason: The reason for the chat response. usage_details: The usage details for the chat response. @@ -1979,7 +1979,7 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): response = ChatResponse( messages=[msg], finish_reason="stop", - model_id="gpt-4", + model="gpt-4", ) print(response.text) # "The weather is sunny." @@ -1989,13 +1989,13 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): # Serialization - to_dict and from_dict response_dict = response.to_dict() - # {'type': 'chat_response', 'messages': [...], 'model_id': 'gpt-4', 'finish_reason': 'stop'} + # {'type': 'chat_response', 'messages': [...], 'model': 'gpt-4', 'finish_reason': 'stop'} restored_response = ChatResponse.from_dict(response_dict) - print(restored_response.model_id) # "gpt-4" + print(restored_response.model) # "gpt-4" # Serialization - to_json and from_json response_json = response.to_json() - # '{"type": "chat_response", "messages": [...], "model_id": "gpt-4", ...}' + # '{"type": "chat_response", "messages": [...], "model": "gpt-4", ...}' restored_from_json = ChatResponse.from_json(response_json) print(restored_from_json.text) # "The weather is sunny." """ @@ -2010,7 +2010,6 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): response_id: str | None = None, conversation_id: str | None = None, model: str | None = None, - model_id: str | None = None, created_at: CreatedAtT | None = None, finish_reason: FinishReasonLiteral | FinishReason | None = None, usage_details: UsageDetails | None = None, @@ -2027,7 +2026,6 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): response_id: Optional ID of the chat response. conversation_id: Optional identifier for the state of the conversation. model: Optional model used in the creation of the chat response. - model_id: Deprecated alias for ``model``. created_at: Optional timestamp for when the response was created. finish_reason: Optional reason for the chat response (e.g., "stop", "length", "tool_calls"). usage_details: Optional usage details for the chat response. @@ -2038,8 +2036,6 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): additional_properties: Optional additional properties associated with the chat response. raw_representation: Optional raw representation of the chat response from an underlying implementation. """ - if model_id is not None and model is None: - model = model_id if messages is None: self.messages: list[Message] = [] elif isinstance(messages, Message): @@ -2082,15 +2078,6 @@ class ChatResponse(SerializationMixin, Generic[ResponseModelT]): """Return whether conversation_id is internal control-flow state.""" return bool(self.additional_properties.get(self._INTERNAL_CONVERSATION_ID_KEY, False)) - @property - def model_id(self) -> str | None: - """Deprecated alias for :attr:`model`.""" - return self.model - - @model_id.setter - def model_id(self, value: str | None) -> None: - self.model = value - @overload @classmethod def from_updates( @@ -2243,7 +2230,7 @@ class ChatResponseUpdate(SerializationMixin): response_id: The ID of the response of which this update is a part. message_id: The ID of the message of which this update is a part. conversation_id: An identifier for the state of the conversation of which this update is a part. - model_id: The model ID associated with this response update. + model: The model associated with this response update. created_at: A timestamp for the chat response update. finish_reason: The finish reason for the operation. additional_properties: Any additional properties associated with the chat response update. @@ -2289,7 +2276,6 @@ class ChatResponseUpdate(SerializationMixin): message_id: str | None = None, conversation_id: str | None = None, model: str | None = None, - model_id: str | None = None, created_at: CreatedAtT | None = None, finish_reason: FinishReasonLiteral | FinishReason | None = None, continuation_token: ContinuationToken | None = None, @@ -2306,7 +2292,6 @@ class ChatResponseUpdate(SerializationMixin): message_id: Optional ID of the message of which this update is a part. conversation_id: Optional identifier for the state of the conversation of which this update is a part model: Optional model associated with this response update. - model_id: Deprecated alias for ``model``. created_at: Optional timestamp for the chat response update. finish_reason: Optional finish reason for the operation. continuation_token: Optional token for resuming a long-running background operation. @@ -2316,8 +2301,6 @@ class ChatResponseUpdate(SerializationMixin): from an underlying implementation. """ - if model_id is not None and model is None: - model = model_id # Handle contents - support dict conversion for from_dict if contents is None: self.contents: list[Content] = [] @@ -2347,15 +2330,6 @@ class ChatResponseUpdate(SerializationMixin): ) self.raw_representation = raw_representation - @property - def model_id(self) -> str | None: - """Deprecated alias for :attr:`model`.""" - return self.model - - @model_id.setter - def model_id(self, value: str | None) -> None: - self.model = value - @property def text(self) -> str: """Returns the concatenated text of all contents in the update.""" @@ -3121,12 +3095,12 @@ class _ChatOptionsBase(TypedDict, total=False): options: ChatOptions = { "temperature": 0.7, "max_tokens": 1000, - "model_id": "gpt-4", + "model": "gpt-4", } # With tools options_with_tools: ChatOptions = { - "model_id": "gpt-4", + "model": "gpt-4", "tool_choice": "auto", "temperature": 0.7, } @@ -3136,8 +3110,7 @@ class _ChatOptionsBase(TypedDict, total=False): """ # Model selection - model_id: str - + model: str # Generation parameters temperature: float top_p: float @@ -3373,10 +3346,10 @@ def merge_chat_options( from agent_framework import merge_chat_options - base = {"temperature": 0.5, "model_id": "gpt-4"} + base = {"temperature": 0.5, "model": "gpt-4"} override = {"temperature": 0.7, "max_tokens": 1000} merged = merge_chat_options(base, override) - # {"temperature": 0.7, "model_id": "gpt-4", "max_tokens": 1000} + # {"temperature": 0.7, "model": "gpt-4", "max_tokens": 1000} """ if not base: return dict(override) if override else {} @@ -3453,12 +3426,12 @@ class EmbeddingGenerationOptions(TypedDict, total=False): from agent_framework import EmbeddingGenerationOptions options: EmbeddingGenerationOptions = { - "model_id": "text-embedding-3-small", + "model": "text-embedding-3-small", "dimensions": 1536, } """ - model_id: str + model: str dimensions: int @@ -3492,13 +3465,10 @@ class Embedding(Generic[EmbeddingT]): vector: EmbeddingT, *, model: str | None = None, - model_id: str | None = None, dimensions: int | None = None, created_at: datetime | None = None, additional_properties: dict[str, Any] | None = None, ) -> None: - if model_id is not None and model is None: - model = model_id self.vector = vector self._dimensions = dimensions self.model = model @@ -3507,15 +3477,6 @@ class Embedding(Generic[EmbeddingT]): _restore_compaction_annotation_in_additional_properties(additional_properties) or {} ) - @property - def model_id(self) -> str | None: - """Deprecated alias for :attr:`model`.""" - return self.model - - @model_id.setter - def model_id(self, value: str | None) -> None: - self.model = value - @property def dimensions(self) -> int | None: """Return the number of dimensions in the embedding vector. diff --git a/python/packages/core/agent_framework/amazon/__init__.py b/python/packages/core/agent_framework/amazon/__init__.py index e9282b8873..92eaa1ca5e 100644 --- a/python/packages/core/agent_framework/amazon/__init__.py +++ b/python/packages/core/agent_framework/amazon/__init__.py @@ -3,9 +3,11 @@ """Amazon Bedrock integration namespace for optional Agent Framework connectors. This module lazily re-exports objects from: +- ``agent-framework-anthropic`` - ``agent-framework-bedrock`` Supported classes: +- AnthropicBedrockClient - BedrockChatClient - BedrockChatOptions - BedrockEmbeddingClient @@ -13,34 +15,36 @@ Supported classes: - BedrockEmbeddingSettings - BedrockGuardrailConfig - BedrockSettings +- RawAnthropicBedrockClient """ import importlib from typing import Any -IMPORT_PATH = "agent_framework_bedrock" -PACKAGE_NAME = "agent-framework-bedrock" -_IMPORTS = [ - "BedrockChatClient", - "BedrockChatOptions", - "BedrockEmbeddingClient", - "BedrockEmbeddingOptions", - "BedrockEmbeddingSettings", - "BedrockGuardrailConfig", - "BedrockSettings", -] +_IMPORTS: dict[str, tuple[str, str]] = { + "AnthropicBedrockClient": ("agent_framework_anthropic", "agent-framework-anthropic"), + "BedrockChatClient": ("agent_framework_bedrock", "agent-framework-bedrock"), + "BedrockChatOptions": ("agent_framework_bedrock", "agent-framework-bedrock"), + "BedrockEmbeddingClient": ("agent_framework_bedrock", "agent-framework-bedrock"), + "BedrockEmbeddingOptions": ("agent_framework_bedrock", "agent-framework-bedrock"), + "BedrockEmbeddingSettings": ("agent_framework_bedrock", "agent-framework-bedrock"), + "BedrockGuardrailConfig": ("agent_framework_bedrock", "agent-framework-bedrock"), + "BedrockSettings": ("agent_framework_bedrock", "agent-framework-bedrock"), + "RawAnthropicBedrockClient": ("agent_framework_anthropic", "agent-framework-anthropic"), +} def __getattr__(name: str) -> Any: if name in _IMPORTS: + import_path, package_name = _IMPORTS[name] try: - return getattr(importlib.import_module(IMPORT_PATH), name) + return getattr(importlib.import_module(import_path), name) except ModuleNotFoundError as exc: raise ModuleNotFoundError( - f"The '{PACKAGE_NAME}' package is not installed, please do `pip install {PACKAGE_NAME}`" + f"The '{package_name}' package is not installed, please do `pip install {package_name}`" ) from exc - raise AttributeError(f"Module {IMPORT_PATH} has no attribute {name}.") + raise AttributeError(f"Module `amazon` has no attribute {name}.") def __dir__() -> list[str]: - return _IMPORTS + return list(_IMPORTS.keys()) diff --git a/python/packages/core/agent_framework/amazon/__init__.pyi b/python/packages/core/agent_framework/amazon/__init__.pyi index a9dd7a9117..064639232a 100644 --- a/python/packages/core/agent_framework/amazon/__init__.pyi +++ b/python/packages/core/agent_framework/amazon/__init__.pyi @@ -1,5 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. +from agent_framework_anthropic import AnthropicBedrockClient, RawAnthropicBedrockClient from agent_framework_bedrock import ( BedrockChatClient, BedrockChatOptions, @@ -11,6 +12,7 @@ from agent_framework_bedrock import ( ) __all__ = [ + "AnthropicBedrockClient", "BedrockChatClient", "BedrockChatOptions", "BedrockEmbeddingClient", @@ -18,4 +20,5 @@ __all__ = [ "BedrockEmbeddingSettings", "BedrockGuardrailConfig", "BedrockSettings", + "RawAnthropicBedrockClient", ] diff --git a/python/packages/core/agent_framework/anthropic/__init__.py b/python/packages/core/agent_framework/anthropic/__init__.py index 8be2a7d208..9d2baaa088 100644 --- a/python/packages/core/agent_framework/anthropic/__init__.py +++ b/python/packages/core/agent_framework/anthropic/__init__.py @@ -7,22 +7,36 @@ This module lazily re-exports objects from: - ``agent-framework-claude`` Supported classes: +- AnthropicBedrockClient - AnthropicClient - AnthropicChatOptions +- AnthropicFoundryClient +- AnthropicVertexClient - ClaudeAgent - ClaudeAgentOptions +- RawAnthropicBedrockClient +- RawAnthropicClient +- RawAnthropicFoundryClient - RawClaudeAgent +- RawAnthropicVertexClient """ import importlib from typing import Any _IMPORTS: dict[str, tuple[str, str]] = { + "AnthropicBedrockClient": ("agent_framework_anthropic", "agent-framework-anthropic"), "AnthropicClient": ("agent_framework_anthropic", "agent-framework-anthropic"), "AnthropicChatOptions": ("agent_framework_anthropic", "agent-framework-anthropic"), + "AnthropicFoundryClient": ("agent_framework_anthropic", "agent-framework-anthropic"), + "AnthropicVertexClient": ("agent_framework_anthropic", "agent-framework-anthropic"), "ClaudeAgent": ("agent_framework_claude", "agent-framework-claude"), "ClaudeAgentOptions": ("agent_framework_claude", "agent-framework-claude"), + "RawAnthropicBedrockClient": ("agent_framework_anthropic", "agent-framework-anthropic"), + "RawAnthropicClient": ("agent_framework_anthropic", "agent-framework-anthropic"), + "RawAnthropicFoundryClient": ("agent_framework_anthropic", "agent-framework-anthropic"), "RawClaudeAgent": ("agent_framework_claude", "agent-framework-claude"), + "RawAnthropicVertexClient": ("agent_framework_anthropic", "agent-framework-anthropic"), } diff --git a/python/packages/core/agent_framework/anthropic/__init__.pyi b/python/packages/core/agent_framework/anthropic/__init__.pyi index 29d70f62b8..1fa62c7f1b 100644 --- a/python/packages/core/agent_framework/anthropic/__init__.pyi +++ b/python/packages/core/agent_framework/anthropic/__init__.pyi @@ -1,14 +1,28 @@ # Copyright (c) Microsoft. All rights reserved. from agent_framework_anthropic import ( + AnthropicBedrockClient, AnthropicChatOptions, AnthropicClient, + AnthropicFoundryClient, + AnthropicVertexClient, + RawAnthropicBedrockClient, + RawAnthropicClient, + RawAnthropicFoundryClient, + RawAnthropicVertexClient, ) from agent_framework_claude import ClaudeAgent, ClaudeAgentOptions __all__ = [ + "AnthropicBedrockClient", "AnthropicChatOptions", "AnthropicClient", + "AnthropicFoundryClient", + "AnthropicVertexClient", "ClaudeAgent", "ClaudeAgentOptions", + "RawAnthropicBedrockClient", + "RawAnthropicClient", + "RawAnthropicFoundryClient", + "RawAnthropicVertexClient", ] diff --git a/python/packages/core/agent_framework/foundry/__init__.py b/python/packages/core/agent_framework/foundry/__init__.py index 0ebf0a9389..6e922f4b3a 100644 --- a/python/packages/core/agent_framework/foundry/__init__.py +++ b/python/packages/core/agent_framework/foundry/__init__.py @@ -2,13 +2,17 @@ """Foundry integration namespace for optional Agent Framework connectors. -This module lazily re-exports objects from cloud Foundry and Foundry Local connector packages. +This module lazily re-exports objects from: +- ``agent-framework-anthropic`` +- ``agent-framework-foundry`` +- ``agent-framework-foundry-local`` """ import importlib from typing import Any _IMPORTS: dict[str, tuple[str, str]] = { + "AnthropicFoundryClient": ("agent_framework_anthropic", "agent-framework-anthropic"), "FoundryAgent": ("agent_framework_foundry", "agent-framework-foundry"), "FoundryChatClient": ("agent_framework_foundry", "agent-framework-foundry"), "FoundryChatOptions": ("agent_framework_foundry", "agent-framework-foundry"), @@ -17,6 +21,7 @@ _IMPORTS: dict[str, tuple[str, str]] = { "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"), + "RawAnthropicFoundryClient": ("agent_framework_anthropic", "agent-framework-anthropic"), "RawFoundryAgent": ("agent_framework_foundry", "agent-framework-foundry"), "RawFoundryAgentChatClient": ("agent_framework_foundry", "agent-framework-foundry"), "RawFoundryChatClient": ("agent_framework_foundry", "agent-framework-foundry"), diff --git a/python/packages/core/agent_framework/foundry/__init__.pyi b/python/packages/core/agent_framework/foundry/__init__.pyi index 534b7fa5bc..0d37d3a7d2 100644 --- a/python/packages/core/agent_framework/foundry/__init__.pyi +++ b/python/packages/core/agent_framework/foundry/__init__.pyi @@ -3,6 +3,7 @@ # Type stubs for the agent_framework.foundry lazy-loading namespace. # Install the relevant packages for full type support. +from agent_framework_anthropic import AnthropicFoundryClient, RawAnthropicFoundryClient from agent_framework_foundry import ( FoundryAgent, FoundryChatClient, @@ -22,6 +23,7 @@ from agent_framework_foundry_local import ( ) __all__ = [ + "AnthropicFoundryClient", "FoundryAgent", "FoundryChatClient", "FoundryChatOptions", @@ -30,6 +32,7 @@ __all__ = [ "FoundryLocalClient", "FoundryLocalSettings", "FoundryMemoryProvider", + "RawAnthropicFoundryClient", "RawFoundryAgent", "RawFoundryAgentChatClient", "RawFoundryChatClient", diff --git a/python/packages/core/agent_framework/google/__init__.py b/python/packages/core/agent_framework/google/__init__.py new file mode 100644 index 0000000000..20bcc591c8 --- /dev/null +++ b/python/packages/core/agent_framework/google/__init__.py @@ -0,0 +1,35 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Google integration namespace for optional Agent Framework connectors. + +This module lazily re-exports Google-hosted Anthropic clients from: +- ``agent-framework-anthropic`` + +Supported classes: +- AnthropicVertexClient +- RawAnthropicVertexClient +""" + +import importlib +from typing import Any + +_IMPORTS: dict[str, tuple[str, str]] = { + "AnthropicVertexClient": ("agent_framework_anthropic", "agent-framework-anthropic"), + "RawAnthropicVertexClient": ("agent_framework_anthropic", "agent-framework-anthropic"), +} + + +def __getattr__(name: str) -> Any: + if name in _IMPORTS: + import_path, package_name = _IMPORTS[name] + try: + return getattr(importlib.import_module(import_path), name) + except ModuleNotFoundError as exc: + raise ModuleNotFoundError( + f"The '{package_name}' package is not installed, please do `pip install {package_name}`" + ) from exc + raise AttributeError(f"Module `google` has no attribute {name}.") + + +def __dir__() -> list[str]: + return list(_IMPORTS.keys()) diff --git a/python/packages/core/agent_framework/google/__init__.pyi b/python/packages/core/agent_framework/google/__init__.pyi new file mode 100644 index 0000000000..350f3cd328 --- /dev/null +++ b/python/packages/core/agent_framework/google/__init__.pyi @@ -0,0 +1,8 @@ +# Copyright (c) Microsoft. All rights reserved. + +from agent_framework_anthropic import AnthropicVertexClient, RawAnthropicVertexClient + +__all__ = [ + "AnthropicVertexClient", + "RawAnthropicVertexClient", +] diff --git a/python/packages/core/agent_framework/observability.py b/python/packages/core/agent_framework/observability.py index cdc6179602..8d2eb05136 100644 --- a/python/packages/core/agent_framework/observability.py +++ b/python/packages/core/agent_framework/observability.py @@ -1265,15 +1265,13 @@ class ChatTelemetryLayer(Generic[OptionsCoT]): opts: dict[str, Any] = options or {} # type: ignore[assignment] provider_name = str(getattr(self, "otel_provider_name", "unknown")) - model_id = ( - merged_client_kwargs.get("model_id") or opts.get("model_id") or getattr(self, "model_id", None) or "unknown" - ) + model = merged_client_kwargs.get("model") or opts.get("model") or getattr(self, "model", None) or "unknown" service_url_func = getattr(self, "service_url", None) service_url = str(service_url_func() if callable(service_url_func) else "unknown") attributes = _get_span_attributes( operation_name=OtelAttr.CHAT_COMPLETION_OPERATION, provider_name=provider_name, - model=model_id, + model=model, service_url=service_url, **merged_client_kwargs, ) @@ -1449,13 +1447,13 @@ class EmbeddingTelemetryLayer(Generic[EmbeddingInputT, EmbeddingT, EmbeddingOpti opts: dict[str, Any] = options or {} # type: ignore[assignment] provider_name = str(getattr(self, "otel_provider_name", "unknown")) - model_id = opts.get("model_id") or getattr(self, "model_id", None) or "unknown" + model = opts.get("model") or getattr(self, "model", None) or "unknown" service_url_func = getattr(self, "service_url", None) service_url = str(service_url_func() if callable(service_url_func) else "unknown") attributes = _get_span_attributes( operation_name=OtelAttr.EMBEDDING_OPERATION, provider_name=provider_name, - model=model_id, + model=model, service_url=service_url, ) @@ -1866,8 +1864,7 @@ OTEL_ATTR_MAP: dict[str | tuple[str, ...], tuple[str, Callable[[Any], Any] | Non "agent_id": (OtelAttr.AGENT_ID, None, False, None), "agent_name": (OtelAttr.AGENT_NAME, None, False, None), "agent_description": (OtelAttr.AGENT_DESCRIPTION, None, False, None), - # Multiple source keys - checks model_id in options, then model in kwargs, then model_id in kwargs - ("model_id", "model"): (OtelAttr.REQUEST_MODEL, None, True, None), + "model": (OtelAttr.REQUEST_MODEL, None, True, None), # Tools with validation - returns None if no valid tools "tools": ( OtelAttr.TOOL_DEFINITIONS, @@ -2054,8 +2051,8 @@ def _get_response_attributes( ) if finish_reason: attributes[OtelAttr.FINISH_REASONS] = json.dumps([finish_reason]) - if model_id := getattr(response, "model_id", None): - attributes[OtelAttr.RESPONSE_MODEL] = model_id + if model := getattr(response, "model", None): + attributes[OtelAttr.RESPONSE_MODEL] = model if capture_usage and (usage := response.usage_details): input_tokens = usage.get("input_token_count") if input_tokens: diff --git a/python/packages/core/tests/core/test_agents.py b/python/packages/core/tests/core/test_agents.py index 015de2a2e3..f61221b526 100644 --- a/python/packages/core/tests/core/test_agents.py +++ b/python/packages/core/tests/core/test_agents.py @@ -154,6 +154,24 @@ def test_chat_client_agent_type(client: SupportsChatGetResponse) -> None: assert isinstance(chat_client_agent, SupportsAgentRun) +def test_chat_client_agent_uses_client_model_attribute(chat_client_base) -> None: + chat_client_base.model = "claude-model" # type: ignore[attr-defined] + + agent = Agent(client=chat_client_base) + + assert agent.default_options["model"] == "claude-model" + assert "model_id" not in agent.default_options + + +def test_chat_client_agent_prefers_default_model_over_client_model(chat_client_base) -> None: + chat_client_base.model = "legacy-model" # type: ignore[attr-defined] + + agent = Agent(client=chat_client_base, default_options={"model": "claude-model"}) + + assert agent.default_options["model"] == "claude-model" + assert "model_id" not in agent.default_options + + def test_agent_init_docstring_surfaces_raw_agent_constructor_docs() -> None: docstring = inspect.getdoc(Agent.__init__) @@ -1926,6 +1944,20 @@ def test_merge_options_none_values_ignored(): assert result["key2"] == "value2" +def test_merge_options_runtime_model_overrides_default_model() -> None: + """Test _merge_options lets a runtime model override a default model.""" + result = _merge_options({"model": "default-model"}, {"model": "runtime-model"}) + + assert result["model"] == "runtime-model" + + +def test_merge_options_preserves_base_model_without_override() -> None: + """Test _merge_options preserves the base model when there is no override.""" + result = _merge_options({"model": "preferred-model"}, {}) + + assert result["model"] == "preferred-model" + + def test_merge_options_tools_combined(): """Test _merge_options raises when distinct tools share the same name.""" diff --git a/python/packages/core/tests/core/test_embedding_client.py b/python/packages/core/tests/core/test_embedding_client.py index 1c49c1d012..38a7b74bdc 100644 --- a/python/packages/core/tests/core/test_embedding_client.py +++ b/python/packages/core/tests/core/test_embedding_client.py @@ -25,7 +25,7 @@ class MockEmbeddingClient(BaseEmbeddingClient): options: EmbeddingGenerationOptions | None = None, ) -> GeneratedEmbeddings[list[float]]: return GeneratedEmbeddings( - [Embedding(vector=[0.1, 0.2, 0.3], model_id="mock-model") for _ in values], + [Embedding(vector=[0.1, 0.2, 0.3], model="mock-model") for _ in values], usage={"prompt_tokens": len(values), "total_tokens": len(values)}, ) @@ -38,12 +38,12 @@ async def test_base_get_embeddings() -> None: result = await client.get_embeddings(["hello", "world"]) assert len(result) == 2 assert result[0].vector == [0.1, 0.2, 0.3] - assert result[0].model_id == "mock-model" + assert result[0].model == "mock-model" async def test_base_get_embeddings_with_options() -> None: client = MockEmbeddingClient() - options: EmbeddingGenerationOptions = {"model_id": "test", "dimensions": 3} + options: EmbeddingGenerationOptions = {"model": "test", "dimensions": 3} result = await client.get_embeddings(["hello"], options=options) assert len(result) == 1 diff --git a/python/packages/core/tests/core/test_embedding_types.py b/python/packages/core/tests/core/test_embedding_types.py index 0d6db6b27e..95c5ede612 100644 --- a/python/packages/core/tests/core/test_embedding_types.py +++ b/python/packages/core/tests/core/test_embedding_types.py @@ -12,7 +12,7 @@ from agent_framework import Embedding, EmbeddingGenerationOptions, GeneratedEmbe def test_embedding_basic_construction() -> None: embedding = Embedding(vector=[0.1, 0.2, 0.3]) assert embedding.vector == [0.1, 0.2, 0.3] - assert embedding.model_id is None + assert embedding.model is None assert embedding.created_at is None assert embedding.additional_properties == {} @@ -21,11 +21,11 @@ def test_embedding_construction_with_metadata() -> None: now = datetime.now() embedding = Embedding( vector=[0.1, 0.2], - model_id="text-embedding-3-small", + model="text-embedding-3-small", created_at=now, additional_properties={"key": "value"}, ) - assert embedding.model_id == "text-embedding-3-small" + assert embedding.model == "text-embedding-3-small" assert embedding.created_at == now assert embedding.additional_properties == {"key": "value"} @@ -96,7 +96,7 @@ def test_generated_construction_with_usage() -> None: [ Embedding( vector=[0.1], - model_id="test-model", + model="test-model", ) ], usage=usage, @@ -113,13 +113,13 @@ def test_generated_construction_with_additional_properties() -> None: def test_generated_construction_with_options() -> None: - opts: EmbeddingGenerationOptions = {"model_id": "text-embedding-3-small", "dimensions": 256} + opts: EmbeddingGenerationOptions = {"model": "text-embedding-3-small", "dimensions": 256} embeddings = GeneratedEmbeddings( [Embedding(vector=[0.1])], options=opts, ) assert embeddings.options is not None - assert embeddings.options["model_id"] == "text-embedding-3-small" + assert embeddings.options["model"] == "text-embedding-3-small" assert embeddings.options["dimensions"] == 256 @@ -160,12 +160,12 @@ def test_generated_none_embeddings_creates_empty_list() -> None: def test_options_empty() -> None: options: EmbeddingGenerationOptions = {} - assert "model_id" not in options + assert "model" not in options -def test_options_with_model_id() -> None: - options: EmbeddingGenerationOptions = {"model_id": "text-embedding-3-small"} - assert options["model_id"] == "text-embedding-3-small" +def test_options_with_model() -> None: + options: EmbeddingGenerationOptions = {"model": "text-embedding-3-small"} + assert options["model"] == "text-embedding-3-small" def test_options_with_dimensions() -> None: @@ -175,8 +175,8 @@ def test_options_with_dimensions() -> None: def test_options_with_all_fields() -> None: options: EmbeddingGenerationOptions = { - "model_id": "text-embedding-3-small", + "model": "text-embedding-3-small", "dimensions": 1536, } - assert options["model_id"] == "text-embedding-3-small" + assert options["model"] == "text-embedding-3-small" assert options["dimensions"] == 1536 diff --git a/python/packages/core/tests/core/test_mcp.py b/python/packages/core/tests/core/test_mcp.py index 72b219b7a6..01cf1717bd 100644 --- a/python/packages/core/tests/core/test_mcp.py +++ b/python/packages/core/tests/core/test_mcp.py @@ -1727,7 +1727,7 @@ async def test_mcp_tool_sampling_callback_no_valid_content(): ], ) ] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -1778,7 +1778,7 @@ async def test_mcp_tool_sampling_callback_no_response_and_successful_message_cre tool.client.get_response.return_value = Mock( messages=[Message(role="assistant", contents=[Content.from_text("Hello")])], - model_id="test-model", + model="test-model", ) success = await tool.sampling_callback(Mock(), params) @@ -1808,7 +1808,7 @@ async def test_mcp_tool_sampling_callback_forwards_system_prompt(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -1843,7 +1843,7 @@ async def test_mcp_tool_sampling_callback_forwards_tools(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -1889,7 +1889,7 @@ async def test_mcp_tool_sampling_callback_forwards_tool_choice(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -1924,7 +1924,7 @@ async def test_mcp_tool_sampling_callback_forwards_empty_system_prompt(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -1959,7 +1959,7 @@ async def test_mcp_tool_sampling_callback_forwards_empty_tools_list(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -1994,7 +1994,7 @@ async def test_mcp_tool_sampling_callback_forwards_generation_params_in_options( mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -2035,7 +2035,7 @@ async def test_mcp_tool_sampling_callback_omits_temperature_when_none(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client @@ -2072,7 +2072,7 @@ async def test_mcp_tool_sampling_callback_always_passes_max_tokens(): mock_chat_client = AsyncMock() mock_response = Mock() mock_response.messages = [Message(role="assistant", contents=[Content.from_text("response")])] - mock_response.model_id = "test-model" + mock_response.model = "test-model" mock_chat_client.get_response.return_value = mock_response tool.client = mock_chat_client diff --git a/python/packages/core/tests/core/test_observability.py b/python/packages/core/tests/core/test_observability.py index 332ee2b6e6..ec99c73af1 100644 --- a/python/packages/core/tests/core/test_observability.py +++ b/python/packages/core/tests/core/test_observability.py @@ -207,7 +207,7 @@ async def test_chat_client_observability(mock_chat_client, span_exporter: InMemo messages = [Message(role="user", text="Test message")] span_exporter.clear() - response = await client.get_response(messages=messages, options={"model_id": "Test"}) + response = await client.get_response(messages=messages, options={"model": "Test"}) assert response is not None spans = span_exporter.get_finished_spans() assert len(spans) == 1 @@ -222,6 +222,23 @@ async def test_chat_client_observability(mock_chat_client, span_exporter: InMemo assert span.attributes[OtelAttr.OUTPUT_MESSAGES] is not None +@pytest.mark.parametrize("enable_sensitive_data", [True, False], indirect=True) +async def test_chat_client_observability_accepts_model_option( + mock_chat_client, span_exporter: InMemorySpanExporter, enable_sensitive_data +): + """Test that telemetry also captures the modern model option.""" + client = mock_chat_client() + + messages = [Message(role="user", text="Test message")] + span_exporter.clear() + response = await client.get_response(messages=messages, options={"model": "Test"}) + assert response is not None + spans = span_exporter.get_finished_spans() + assert len(spans) == 1 + span = spans[0] + assert span.attributes[OtelAttr.REQUEST_MODEL] == "Test" + + @pytest.mark.parametrize("enable_sensitive_data", [True, False], indirect=True) async def test_chat_client_streaming_observability( mock_chat_client, span_exporter: InMemorySpanExporter, enable_sensitive_data @@ -232,7 +249,7 @@ async def test_chat_client_streaming_observability( span_exporter.clear() # Collect all yielded updates updates = [] - stream = client.get_response(stream=True, messages=messages, options={"model_id": "Test"}) + stream = client.get_response(stream=True, messages=messages, options={"model": "Test"}) async for update in stream: updates.append(update) await stream.get_final_response() @@ -260,7 +277,7 @@ async def test_chat_client_observability_with_instructions( client = mock_chat_client() messages = [Message(role="user", text="Test message")] - options = {"model_id": "Test", "instructions": "You are a helpful assistant."} + options = {"model": "Test", "instructions": "You are a helpful assistant."} span_exporter.clear() response = await client.get_response(messages=messages, options=options) @@ -289,7 +306,7 @@ async def test_chat_client_streaming_observability_with_instructions( client = mock_chat_client() messages = [Message(role="user", text="Test")] - options = {"model_id": "Test", "instructions": "You are a helpful assistant."} + options = {"model": "Test", "instructions": "You are a helpful assistant."} span_exporter.clear() updates = [] @@ -318,7 +335,7 @@ async def test_chat_client_observability_without_instructions( client = mock_chat_client() messages = [Message(role="user", text="Test message")] - options = {"model_id": "Test"} # No instructions + options = {"model": "Test"} # No instructions span_exporter.clear() response = await client.get_response(messages=messages, options=options) @@ -339,7 +356,7 @@ async def test_chat_client_observability_with_empty_instructions( client = mock_chat_client() messages = [Message(role="user", text="Test message")] - options = {"model_id": "Test", "instructions": ""} # Empty string + options = {"model": "Test", "instructions": ""} # Empty string span_exporter.clear() response = await client.get_response(messages=messages, options=options) @@ -362,7 +379,7 @@ async def test_chat_client_observability_with_list_instructions( client = mock_chat_client() messages = [Message(role="user", text="Test message")] - options = {"model_id": "Test", "instructions": ["Instruction 1", "Instruction 2"]} + options = {"model": "Test", "instructions": ["Instruction 1", "Instruction 2"]} span_exporter.clear() response = await client.get_response(messages=messages, options=options) @@ -379,8 +396,8 @@ async def test_chat_client_observability_with_list_instructions( assert system_instructions[1]["content"] == "Instruction 2" -async def test_chat_client_without_model_id_observability(mock_chat_client, span_exporter: InMemorySpanExporter): - """Test telemetry shouldn't fail when the model_id is not provided for unknown reason.""" +async def test_chat_client_without_model_observability(mock_chat_client, span_exporter: InMemorySpanExporter): + """Test telemetry shouldn't fail when the model is not provided for unknown reason.""" client = mock_chat_client() messages = [Message(role="user", text="Test")] span_exporter.clear() @@ -396,10 +413,8 @@ async def test_chat_client_without_model_id_observability(mock_chat_client, span assert span.attributes[OtelAttr.REQUEST_MODEL] == "unknown" -async def test_chat_client_streaming_without_model_id_observability( - mock_chat_client, span_exporter: InMemorySpanExporter -): - """Test streaming telemetry shouldn't fail when the model_id is not provided for unknown reason.""" +async def test_chat_client_streaming_without_model_observability(mock_chat_client, span_exporter: InMemorySpanExporter): + """Test streaming telemetry shouldn't fail when the model is not provided for unknown reason.""" client = mock_chat_client() messages = [Message(role="user", text="Test")] span_exporter.clear() @@ -441,7 +456,7 @@ def mock_chat_agent(): self.id = "test_agent_id" self.name = "test_agent" self.description = "Test agent description" - self.default_options: dict[str, Any] = {"model_id": "TestModel"} + self.default_options: dict[str, Any] = {"model": "TestModel"} def run(self, messages=None, *, session=None, stream=False, **kwargs): if stream: @@ -1540,7 +1555,7 @@ async def test_chat_client_observability_exception(mock_chat_client, span_export span_exporter.clear() with pytest.raises(ValueError, match="Test error"): - await client.get_response(messages=messages, options={"model_id": "Test"}) + await client.get_response(messages=messages, options={"model": "Test"}) spans = span_exporter.get_finished_spans() assert len(spans) == 1 @@ -1570,7 +1585,7 @@ async def test_chat_client_streaming_observability_exception(mock_chat_client, s span_exporter.clear() with pytest.raises(ValueError, match="Streaming error"): - async for _ in client.get_response(messages=messages, stream=True, options={"model_id": "Test"}): + async for _ in client.get_response(messages=messages, stream=True, options={"model": "Test"}): pass spans = span_exporter.get_finished_spans() @@ -1651,8 +1666,8 @@ def test_get_response_attributes_with_finish_reason(): assert OtelAttr.FINISH_REASONS in result -def test_get_response_attributes_with_model_id(): - """Test _get_response_attributes includes model_id.""" +def test_get_response_attributes_with_model(): + """Test _get_response_attributes includes model.""" from unittest.mock import Mock from agent_framework.observability import _get_response_attributes @@ -1662,7 +1677,7 @@ def test_get_response_attributes_with_model_id(): response.finish_reason = None response.raw_representation = None response.usage_details = None - response.model_id = "gpt-4" + response.model = "gpt-4" attrs = {} result = _get_response_attributes(attrs, response) @@ -2075,7 +2090,7 @@ async def test_capture_messages_with_finish_reason(mock_chat_client, span_export messages = [Message(role="user", text="Test")] span_exporter.clear() - response = await client.get_response(messages=messages, options={"model_id": "Test"}) + response = await client.get_response(messages=messages, options={"model": "Test"}) assert response is not None assert response.finish_reason == "stop" @@ -2165,7 +2180,7 @@ async def test_chat_client_when_disabled(mock_chat_client, span_exporter: InMemo messages = [Message(role="user", text="Test")] span_exporter.clear() - response = await client.get_response(messages=messages, options={"model_id": "Test"}) + response = await client.get_response(messages=messages, options={"model": "Test"}) assert response is not None spans = span_exporter.get_finished_spans() @@ -2181,7 +2196,7 @@ async def test_chat_client_streaming_when_disabled(mock_chat_client, span_export span_exporter.clear() updates = [] - async for update in client.get_response(messages=messages, stream=True, options={"model_id": "Test"}): + async for update in client.get_response(messages=messages, stream=True, options={"model": "Test"}): updates.append(update) assert len(updates) == 2 # Still works functionally @@ -2501,7 +2516,7 @@ async def test_layer_ordering_span_sequence_with_function_calling(span_exporter: def __init__(self): super().__init__() self.call_count = 0 - self.model_id = "test-model" + self.model = "test-model" def service_url(self): return "https://test.example.com" @@ -2608,7 +2623,7 @@ async def test_agent_and_chat_spans_do_not_duplicate_response_telemetry( id="nested_agent_id", name="nested_agent", description="Nested telemetry agent", - default_options={"model_id": "NestedModel"}, + default_options={"model": "NestedModel"}, ) span_exporter.clear() @@ -2661,7 +2676,7 @@ async def test_capture_messages_preserves_non_ascii_characters(mock_chat_client, messages = [Message(role="user", text=japanese_text)] span_exporter.clear() - response = await client.get_response(messages=messages, options={"model_id": "Test"}) + response = await client.get_response(messages=messages, options={"model": "Test"}) assert response is not None spans = span_exporter.get_finished_spans() @@ -2825,7 +2840,7 @@ async def test_agent_instructions_from_default_options( import json agent = mock_chat_agent() - agent.default_options = {"model_id": "TestModel", "instructions": "Default system instructions."} + agent.default_options = {"model": "TestModel", "instructions": "Default system instructions."} messages = [Message(role="user", text="Test message")] span_exporter.clear() @@ -2851,7 +2866,7 @@ async def test_agent_instructions_from_options_override( import json agent = mock_chat_agent() - agent.default_options = {"model_id": "TestModel"} # No default instructions + agent.default_options = {"model": "TestModel"} # No default instructions messages = [Message(role="user", text="Test message")] span_exporter.clear() @@ -2876,7 +2891,7 @@ async def test_agent_instructions_merged_from_default_and_options( import json agent = mock_chat_agent() - agent.default_options = {"model_id": "TestModel", "instructions": "Default instructions."} + agent.default_options = {"model": "TestModel", "instructions": "Default instructions."} messages = [Message(role="user", text="Test message")] span_exporter.clear() @@ -2903,7 +2918,7 @@ async def test_agent_streaming_instructions_from_default_options( import json agent = mock_chat_agent() - agent.default_options = {"model_id": "TestModel", "instructions": "Default streaming instructions."} + agent.default_options = {"model": "TestModel", "instructions": "Default streaming instructions."} messages = [Message(role="user", text="Test message")] span_exporter.clear() @@ -2932,7 +2947,7 @@ async def test_agent_streaming_instructions_merged_from_default_and_options( import json agent = mock_chat_agent() - agent.default_options = {"model_id": "TestModel", "instructions": "Default instructions."} + agent.default_options = {"model": "TestModel", "instructions": "Default instructions."} messages = [Message(role="user", text="Test message")] span_exporter.clear() @@ -2960,7 +2975,7 @@ async def test_agent_no_instructions_in_default_or_options( ): """Test that system_instructions is not set when neither default_options nor options have instructions.""" agent = mock_chat_agent() - agent.default_options = {"model_id": "TestModel"} # No instructions + agent.default_options = {"model": "TestModel"} # No instructions messages = [Message(role="user", text="Test message")] span_exporter.clear() diff --git a/python/packages/core/tests/core/test_tools.py b/python/packages/core/tests/core/test_tools.py index 0f87219690..143aa95727 100644 --- a/python/packages/core/tests/core/test_tools.py +++ b/python/packages/core/tests/core/test_tools.py @@ -608,7 +608,7 @@ async def test_tool_invoke_rejects_unexpected_runtime_kwargs() -> None: await simple_tool.invoke( arguments=args, api_token="secret-token", - options={"model_id": "dummy"}, + options={"model": "dummy"}, ) diff --git a/python/packages/core/tests/core/test_types.py b/python/packages/core/tests/core/test_types.py index 9d1b39f29e..101379b8f9 100644 --- a/python/packages/core/tests/core/test_types.py +++ b/python/packages/core/tests/core/test_types.py @@ -754,6 +754,14 @@ def test_chat_response(): assert str(response) == response.text +def test_chat_response_accepts_model_alias() -> None: + """Test ChatResponse accepts model and exposes it through model alias.""" + response = ChatResponse(messages=Message(role="assistant", text="Hello"), model="claude-test") + + assert response.model == "claude-test" + assert response.model == "claude-test" + + class OutputModel(BaseModel): response: str @@ -851,6 +859,14 @@ def test_chat_response_update(): assert response_update.text == "I'm doing well, thank you!" +def test_chat_response_update_accepts_model_alias() -> None: + """Test ChatResponseUpdate accepts model and exposes it through model alias.""" + response_update = ChatResponseUpdate(contents=[Content.from_text("Hello")], model="claude-test") + + assert response_update.model == "claude-test" + assert response_update.model == "claude-test" + + def test_chat_response_updates_to_chat_response_one(): """Test converting ChatResponseUpdate to ChatResponse.""" # Create a Message @@ -1374,7 +1390,7 @@ def test_response_update_propagates_fields_and_metadata(): response_id="rid", message_id="mid", conversation_id="cid", - model_id="model-x", + model="model-x", created_at="t0", finish_reason="stop", additional_properties={"k": "v"}, @@ -1383,7 +1399,7 @@ def test_response_update_propagates_fields_and_metadata(): assert resp.response_id == "rid" assert resp.created_at == "t0" assert resp.conversation_id == "cid" - assert resp.model_id == "model-x" + assert resp.model == "model-x" assert resp.finish_reason == "stop" assert resp.additional_properties and resp.additional_properties["k"] == "v" assert resp.messages[0].role == "assistant" @@ -1935,7 +1951,7 @@ def test_chat_response_complex_serialization(): assert isinstance(response.messages[0], Message) assert isinstance(response.finish_reason, str) # FinishReason is now a NewType of str assert isinstance(response.usage_details, dict) - assert response.model_id == "gpt-4" # Should be stored as model_id + assert response.model == "gpt-4" # Should be stored as model # Test to_dict with complex objects response_dict = response.to_dict() @@ -1943,7 +1959,7 @@ def test_chat_response_complex_serialization(): assert isinstance(response_dict["messages"][0], dict) assert isinstance(response_dict["finish_reason"], str) # FinishReason serializes to string assert isinstance(response_dict["usage_details"], dict) - assert response_dict["model"] == "gpt-4" # Should serialize as model_id + assert response_dict["model"] == "gpt-4" # Should serialize as model def test_chat_response_update_all_content_types(): diff --git a/python/packages/declarative/agent_framework_declarative/_loader.py b/python/packages/declarative/agent_framework_declarative/_loader.py index 874d5704d4..635d825cdc 100644 --- a/python/packages/declarative/agent_framework_declarative/_loader.py +++ b/python/packages/declarative/agent_framework_declarative/_loader.py @@ -46,7 +46,7 @@ else: class ProviderTypeMapping(TypedDict, total=True): package: str name: str - model_id_field: str + model_field: str endpoint_field: str | None api_key_field: str | None @@ -55,63 +55,63 @@ PROVIDER_TYPE_OBJECT_MAPPING: dict[str, ProviderTypeMapping] = { "AzureOpenAI": { "package": "agent_framework.openai", "name": "OpenAIChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "azure_endpoint", "api_key_field": "api_key", }, "AzureOpenAI.Chat": { "package": "agent_framework.openai", "name": "OpenAIChatCompletionClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "azure_endpoint", "api_key_field": "api_key", }, "AzureOpenAI.Responses": { "package": "agent_framework.openai", "name": "OpenAIChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "azure_endpoint", "api_key_field": "api_key", }, "Foundry": { "package": "agent_framework.foundry", "name": "FoundryChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "project_endpoint", "api_key_field": None, }, "OpenAI.Chat": { "package": "agent_framework.openai", "name": "OpenAIChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "base_url", "api_key_field": "api_key", }, "OpenAI.Responses": { "package": "agent_framework.openai", "name": "OpenAIChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "base_url", "api_key_field": "api_key", }, "OpenAI": { "package": "agent_framework.openai", "name": "OpenAIChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "base_url", "api_key_field": "api_key", }, "Foundry.Chat": { "package": "agent_framework.foundry", "name": "FoundryChatClient", - "model_id_field": "model", + "model_field": "model", "endpoint_field": "project_endpoint", "api_key_field": None, }, "Anthropic.Chat": { "package": "agent_framework.anthropic", "name": "AnthropicChatClient", - "model_id_field": "model_id", + "model_field": "model", "endpoint_field": None, "api_key_field": "api_key", }, @@ -210,7 +210,7 @@ class AgentFactory: "Provider.ApiType": { "package": "package.name", "name": "ClassName", - "model_id_field": "field_name_in_constructor", + "model_field": "field_name_in_constructor", "endpoint_field": "endpoint_kwarg_name_or_null", "api_key_field": "api_key_kwarg_name_or_null", }, @@ -220,7 +220,7 @@ class AgentFactory: Here, "Provider.ApiType" is the lookup key used when both provider and apiType are specified in the model, "Provider" is also allowed. Package refers to which model needs to be imported, Name is the class name of the - SupportsChatGetResponse implementation, and model_id_field is the name of the field in the + SupportsChatGetResponse implementation, and model_field is the name of the field in the constructor that accepts the model.id value. default_provider: The default provider used when model.provider is not specified, default is "OpenAI". @@ -264,7 +264,7 @@ class AgentFactory: "CustomProvider.Chat": { "package": "my_package.clients", "name": "CustomChatClient", - "model_id_field": "model_name", + "model_field": "model", }, }, ) @@ -690,7 +690,7 @@ class AgentFactory: # if prompt_agent.model is defined, but no id, use the supplied client if self.client: return self.client - # or raise, since we cannot create a client without model id + # or raise, since we cannot create a client without a model raise DeclarativeLoaderError( "ChatClient must be provided to create agent from PromptAgent, or define model.id in the PromptAgent." ) @@ -699,7 +699,7 @@ class AgentFactory: class_name = mapping["name"] module = __import__(module_name, fromlist=[class_name]) agent_class = getattr(module, class_name) - setup_dict[mapping["model_id_field"]] = prompt_agent.model.id + setup_dict[mapping["model_field"]] = prompt_agent.model.id return agent_class(**setup_dict) # type: ignore[no-any-return] def _parse_chat_options(self, model: Model | None) -> dict[str, Any]: @@ -841,7 +841,7 @@ class AgentFactory: model: The Model instance containing provider and apiType information. Returns: - A dictionary containing the package, name, and model_id_field for the provider. + A dictionary containing the package, name, and model_field for the provider. Raises: ProviderLookupError: If the provider type is not supported or can't be found. diff --git a/python/packages/declarative/tests/test_declarative_loader.py b/python/packages/declarative/tests/test_declarative_loader.py index 2ca87bfa65..02485b9e9c 100644 --- a/python/packages/declarative/tests/test_declarative_loader.py +++ b/python/packages/declarative/tests/test_declarative_loader.py @@ -632,7 +632,7 @@ class TestAgentFactorySafeMode: from agent_framework_declarative._loader import AgentFactory - monkeypatch.setenv("TEST_MODEL_ID", "gpt-4-from-env") + monkeypatch.setenv("TEST_MODEL", "gpt-4-from-env") # Create a mock chat client to avoid needing real provider mock_client = MagicMock() @@ -1131,7 +1131,7 @@ model: "CustomProvider.Chat": { "package": "agent_framework.openai", "name": "OpenAIChatClient", - "model_id_field": "model_id", + "model_field": "model", }, } diff --git a/python/packages/devui/agent_framework_devui/_discovery.py b/python/packages/devui/agent_framework_devui/_discovery.py index 372e870c15..f7b462933d 100644 --- a/python/packages/devui/agent_framework_devui/_discovery.py +++ b/python/packages/devui/agent_framework_devui/_discovery.py @@ -391,7 +391,7 @@ class EntityDiscovery: source=source, # IMPORTANT: Pass the source parameter tools=[str(tool) for tool in (tools_list or [])], instructions=instructions, - model_id=model, + model=model, chat_client_type=chat_client_type, context_provider=context_provider_list, middleware=middlewares_list, @@ -846,7 +846,7 @@ class EntityDiscovery: description=description, tools=tools_union, instructions=instructions, - model_id=model, + model=model, chat_client_type=chat_client_type, context_provider=context_provider_list, middleware=middlewares_list, diff --git a/python/packages/devui/agent_framework_devui/_mapper.py b/python/packages/devui/agent_framework_devui/_mapper.py index 9e79b308c5..07f87fec3f 100644 --- a/python/packages/devui/agent_framework_devui/_mapper.py +++ b/python/packages/devui/agent_framework_devui/_mapper.py @@ -770,9 +770,9 @@ class MessageMapper: from .models._openai_custom import AgentCompletedEvent, AgentFailedEvent, AgentStartedEvent try: - # Get model name from request or use 'devui' as default + # Get model from request or use 'devui' as default request_obj = context.get("request") - model_name = request_obj.model if request_obj and request_obj.model else "devui" + model = request_obj.model if request_obj and request_obj.model else "devui" if isinstance(event, AgentStartedEvent): execution_id = f"agent_{uuid4().hex[:12]}" @@ -783,7 +783,7 @@ class MessageMapper: id=f"resp_{execution_id}", object="response", created_at=float(time.time()), - model=model_name, + model=model, output=[], status="in_progress", parallel_tool_calls=False, @@ -818,7 +818,7 @@ class MessageMapper: id=f"resp_{execution_id}", object="response", created_at=float(time.time()), - model=model_name, + model=model, output=[], status="failed", error=response_error, @@ -865,16 +865,16 @@ class MessageMapper: # Return proper OpenAI event objects events: list[Any] = [] - # Get model name from request or use 'devui' as default + # Get model from request or use 'devui' as default request_obj = context.get("request") - model_name = request_obj.model if request_obj and request_obj.model else "devui" + model = request_obj.model if request_obj and request_obj.model else "devui" # Create a full Response object with all required fields response_obj = Response( id=f"resp_{workflow_id}", object="response", created_at=float(time.time()), - model=model_name, + model=model, output=[], # Empty output list initially status="in_progress", # Required fields with safe defaults @@ -989,9 +989,9 @@ class MessageMapper: # Import Response and ResponseError types from openai.types.responses import Response, ResponseError - # Get model name from request or use 'devui' as default + # Get model from request or use 'devui' as default request_obj = context.get("request") - model_name = request_obj.model if request_obj and request_obj.model else "devui" + model = request_obj.model if request_obj and request_obj.model else "devui" # Extract error message from WorkflowErrorDetails if details: @@ -1013,7 +1013,7 @@ class MessageMapper: id=f"resp_{workflow_id}", object="response", created_at=float(time.time()), - model=model_name, + model=model, output=[], status="failed", error=response_error, diff --git a/python/packages/devui/agent_framework_devui/_session.py b/python/packages/devui/agent_framework_devui/_session.py index 93ac9b31e4..9d657a2d30 100644 --- a/python/packages/devui/agent_framework_devui/_session.py +++ b/python/packages/devui/agent_framework_devui/_session.py @@ -20,7 +20,7 @@ class RequestRecord(TypedDict): entity_id: str executor: str input: Any - model_id: str + model: str stream: bool execution_time: NotRequired[float] status: NotRequired[str] @@ -91,7 +91,7 @@ class SessionManager: logger.debug(f"Closed session: {session_id}") def add_request_record( - self, session_id: str, entity_id: str, executor_name: str, request_input: Any, model_id: str + self, session_id: str, entity_id: str, executor_name: str, request_input: Any, model: str ) -> str: """Add a request record to a session. @@ -100,7 +100,7 @@ class SessionManager: entity_id: ID of the entity being executed executor_name: Name of the executor request_input: Input for the request - model_id: Model name + model: Model name Returns: Request ID @@ -115,7 +115,7 @@ class SessionManager: "entity_id": entity_id, "executor": executor_name, "input": request_input, - "model_id": model_id, + "model": model, "stream": True, } session["requests"].append(request_record) @@ -163,7 +163,7 @@ class SessionManager: "timestamp": req["timestamp"].isoformat(), "entity_id": req["entity_id"], "executor": req["executor"], - "model": req["model_id"], + "model": req["model"], "input_length": len(str(req["input"])) if req["input"] else 0, "execution_time": req.get("execution_time"), "status": req.get("status", "unknown"), diff --git a/python/packages/devui/agent_framework_devui/_utils.py b/python/packages/devui/agent_framework_devui/_utils.py index 889a690c87..9aa7efa9f6 100644 --- a/python/packages/devui/agent_framework_devui/_utils.py +++ b/python/packages/devui/agent_framework_devui/_utils.py @@ -59,13 +59,13 @@ def extract_agent_metadata(entity_object: Any) -> dict[str, Any]: chat_opts = entity_object.default_options chat_opts_dict = _string_key_dict(chat_opts) if chat_opts_dict is not None: - model_id = chat_opts_dict.get("model_id") - if model_id: - metadata["model"] = model_id - elif hasattr(chat_opts, "model_id") and chat_opts.model_id: - metadata["model"] = chat_opts.model_id - if metadata["model"] is None and hasattr(entity_object, "client") and hasattr(entity_object.client, "model_id"): - metadata["model"] = entity_object.client.model_id + model = chat_opts_dict.get("model") + if model: + metadata["model"] = model + elif hasattr(chat_opts, "model") and chat_opts.model: + metadata["model"] = chat_opts.model + if metadata["model"] is None and hasattr(entity_object, "client") and hasattr(entity_object.client, "model"): + metadata["model"] = entity_object.client.model # Try to get chat client type if hasattr(entity_object, "client"): diff --git a/python/packages/devui/agent_framework_devui/models/_discovery_models.py b/python/packages/devui/agent_framework_devui/models/_discovery_models.py index 1e1f19e04d..694f871a7d 100644 --- a/python/packages/devui/agent_framework_devui/models/_discovery_models.py +++ b/python/packages/devui/agent_framework_devui/models/_discovery_models.py @@ -44,7 +44,7 @@ class EntityInfo(BaseModel): # Agent-specific fields (optional, populated when available) instructions: str | None = None - model_id: str | None = None + model: str | None = None chat_client_type: str | None = None context_provider: list[str] | None = None middleware: list[str] | None = None diff --git a/python/packages/devui/agent_framework_devui/ui/assets/index.js b/python/packages/devui/agent_framework_devui/ui/assets/index.js index 239c924fec..d4721e6db5 100644 --- a/python/packages/devui/agent_framework_devui/ui/assets/index.js +++ b/python/packages/devui/agent_framework_devui/ui/assets/index.js @@ -485,7 +485,7 @@ services: # Or Azure OpenAI - AZURE_OPENAI_API_KEY=\${AZURE_OPENAI_API_KEY} - AZURE_OPENAI_ENDPOINT=\${AZURE_OPENAI_ENDPOINT} - - AZURE_OPENAI_DEPLOYMENT_NAME=\${AZURE_OPENAI_DEPLOYMENT_NAME} + - AZURE_OPENAI_MODEL=\${AZURE_OPENAI_MODEL} # Optional: Enable instrumentation - ENABLE_INSTRUMENTATION=\${ENABLE_INSTRUMENTATION:-false} ports: @@ -519,7 +519,7 @@ az acr build --registry myregistry \\ 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 \\ --resource-group myResourceGroup \\ - --query properties.configuration.ingress.fqdn`})]})]})]}),o.jsxs("div",{className:"bg-blue-50 dark:bg-blue-950/50 border border-blue-200 dark:border-blue-800 rounded-md p-3",children:[o.jsx("h4",{className:"text-sm font-semibold mb-2",children:"Learn More"}),o.jsx("p",{className:"text-xs text-muted-foreground mb-3",children:"Explore Azure Container Apps documentation for advanced features like scaling, monitoring, and CI/CD integration."}),o.jsx(Le,{size:"sm",variant:"outline",className:"w-full",asChild:!0,children:o.jsxs("a",{href:"https://learn.microsoft.com/azure/container-apps/",target:"_blank",rel:"noopener noreferrer",children:[o.jsx(Hu,{className:"h-3 w-3 mr-1"}),"View Azure Container Apps Documentation"]})})]})]})]})]})})})]})})}function tD({className:e,...n}){return o.jsx("div",{"data-slot":"card",className:We("bg-card text-card-foreground flex flex-col gap-6 rounded border py-6 shadow-sm",e),...n})}function nD({className:e,...n}){return o.jsx("div",{"data-slot":"card-header",className:We("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",e),...n})}function N2({className:e,...n}){return o.jsx("div",{"data-slot":"card-title",className:We("leading-none font-semibold",e),...n})}function sD({className:e,...n}){return o.jsx("div",{"data-slot":"card-description",className:We("text-muted-foreground text-sm",e),...n})}function rD({className:e,...n}){return o.jsx("div",{"data-slot":"card-content",className:We("px-6",e),...n})}function oD({className:e,...n}){return o.jsx("div",{"data-slot":"card-footer",className:We("flex items-center px-6 [.border-t]:pt-6",e),...n})}const Cr=[{id:"foundry-weather-agent",name:"Azure AI Weather Agent",description:"Weather agent using Azure AI Agent (Foundry) with Azure CLI authentication",type:"agent",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/foundry_agent/agent.py",tags:["azure-ai","foundry","tools"],author:"Microsoft",difficulty:"beginner",features:["Azure AI Agent integration","Azure CLI authentication","Mock weather tools"],requiredEnvVars:[{name:"FOUNDRY_PROJECT_ENDPOINT",description:"Azure AI Foundry project endpoint URL",required:!0,example:"https://your-project.api.azureml.ms"},{name:"FOUNDRY_MODEL",description:"Name of the deployed model in Azure AI Foundry",required:!0,example:"gpt-4o"}]},{id:"weather-agent-azure",name:"Azure OpenAI Weather Agent",description:"Weather agent using Azure OpenAI with API key authentication",type:"agent",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/weather_agent_azure/agent.py",tags:["azure","openai","tools"],author:"Microsoft",difficulty:"beginner",features:["Azure OpenAI integration","API key authentication","Function calling","Mock weather tools"],requiredEnvVars:[{name:"AZURE_OPENAI_API_KEY",description:"Azure OpenAI API key",required:!0},{name:"AZURE_OPENAI_DEPLOYMENT_NAME",description:"Name of the deployed model in Azure OpenAI",required:!0,example:"gpt-4o"},{name:"AZURE_OPENAI_ENDPOINT",description:"Azure OpenAI endpoint URL",required:!0,example:"https://your-resource.openai.azure.com"}]},{id:"spam-workflow",name:"Spam Detection Workflow",description:"5-step workflow demonstrating email spam detection with branching logic",type:"workflow",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/spam_workflow/workflow.py",tags:["workflow","branching","multi-step"],author:"Microsoft",difficulty:"beginner",features:["Sequential execution","Conditional branching","Mock spam detection"]},{id:"fanout-workflow",name:"Complex Fan-In/Fan-Out Workflow",description:"Advanced data processing workflow with parallel validation, transformation, and quality assurance stages",type:"workflow",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/fanout_workflow/workflow.py",tags:["workflow","fan-out","fan-in","parallel"],author:"Microsoft",difficulty:"advanced",features:["Fan-out pattern","Parallel execution","Complex state management","Multi-stage processing"]}];Cr.filter(e=>e.type==="agent"),Cr.filter(e=>e.type==="workflow"),Cr.filter(e=>e.difficulty==="beginner"),Cr.filter(e=>e.difficulty==="intermediate"),Cr.filter(e=>e.difficulty==="advanced");const aD=e=>{switch(e){case"beginner":return"bg-green-100 text-green-700 border-green-200";case"intermediate":return"bg-yellow-100 text-yellow-700 border-yellow-200";case"advanced":return"bg-red-100 text-red-700 border-red-200";default:return"bg-gray-100 text-gray-700 border-gray-200"}},j2=w.forwardRef(({className:e,...n},r)=>o.jsx("div",{ref:r,role:"alert",className:We("relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",e),...n}));j2.displayName="Alert";const S2=w.forwardRef(({className:e,...n},r)=>o.jsx("h5",{ref:r,className:We("mb-1 font-medium leading-none tracking-tight",e),...n}));S2.displayName="AlertTitle";const _2=w.forwardRef(({className:e,...n},r)=>o.jsx("div",{ref:r,className:We("text-sm [&_p]:leading-relaxed",e),...n}));_2.displayName="AlertDescription";function E2({children:e,copyable:n=!1}){const[r,a]=w.useState(!1),l=()=>{navigator.clipboard.writeText(e),a(!0),setTimeout(()=>a(!1),2e3)};return o.jsxs("div",{className:"relative",children:[o.jsx("pre",{className:"bg-muted p-3 rounded-md text-sm overflow-x-auto font-mono",children:o.jsx("code",{children:e})}),n&&o.jsx(Le,{variant:"ghost",size:"sm",className:"absolute top-2 right-2 h-6 w-6 p-0",onClick:l,children:r?o.jsx(jo,{className:"h-3 w-3"}):o.jsx(uo,{className:"h-3 w-3"})})]})}function iu({number:e,title:n,description:r,code:a,action:l,copyable:c=!1}){return o.jsxs("div",{className:"flex gap-4",children:[o.jsx("div",{className:"flex-shrink-0",children:o.jsx("div",{className:"flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground font-semibold",children:e})}),o.jsxs("div",{className:"flex-1 space-y-2",children:[o.jsx("h4",{className:"font-semibold",children:n}),r&&o.jsx("p",{className:"text-sm text-muted-foreground",children:r}),a&&o.jsx(E2,{copyable:c,children:a}),l&&o.jsx("div",{children:l})]})]})}function iD({sample:e,open:n,onOpenChange:r}){const a=e.requiredEnvVars&&e.requiredEnvVars.length>0,l=a?0:-1;return o.jsx(Ir,{open:n,onOpenChange:r,children:o.jsxs(Lr,{className:"max-w-3xl",children:[o.jsxs($r,{className:"px-6 pt-6 pb-2",children:[o.jsxs(Pr,{children:["Setup: ",e.name]}),o.jsxs(OR,{children:["Follow these steps to run this sample ",e.type," locally"]})]}),o.jsx("div",{className:"px-6 pb-6",children:o.jsx(Wn,{className:"h-[500px]",children:o.jsxs("div",{className:"space-y-6 pr-4",children:[o.jsx(iu,{number:1,title:"Download the sample file",action:o.jsx(Le,{asChild:!0,size:"sm",children:o.jsxs("a",{href:e.url,download:`${e.id}.py`,target:"_blank",rel:"noopener noreferrer",children:[o.jsx(Pu,{className:"h-4 w-4 mr-2"}),"Download ",e.id,".py"]})})}),o.jsx(iu,{number:2,title:"Create a project folder",description:"Create a dedicated folder for this sample and move the downloaded file there:",code:`mkdir -p ~/my-agents/${e.id} + --query properties.configuration.ingress.fqdn`})]})]})]}),o.jsxs("div",{className:"bg-blue-50 dark:bg-blue-950/50 border border-blue-200 dark:border-blue-800 rounded-md p-3",children:[o.jsx("h4",{className:"text-sm font-semibold mb-2",children:"Learn More"}),o.jsx("p",{className:"text-xs text-muted-foreground mb-3",children:"Explore Azure Container Apps documentation for advanced features like scaling, monitoring, and CI/CD integration."}),o.jsx(Le,{size:"sm",variant:"outline",className:"w-full",asChild:!0,children:o.jsxs("a",{href:"https://learn.microsoft.com/azure/container-apps/",target:"_blank",rel:"noopener noreferrer",children:[o.jsx(Hu,{className:"h-3 w-3 mr-1"}),"View Azure Container Apps Documentation"]})})]})]})]})]})})})]})})}function tD({className:e,...n}){return o.jsx("div",{"data-slot":"card",className:We("bg-card text-card-foreground flex flex-col gap-6 rounded border py-6 shadow-sm",e),...n})}function nD({className:e,...n}){return o.jsx("div",{"data-slot":"card-header",className:We("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",e),...n})}function N2({className:e,...n}){return o.jsx("div",{"data-slot":"card-title",className:We("leading-none font-semibold",e),...n})}function sD({className:e,...n}){return o.jsx("div",{"data-slot":"card-description",className:We("text-muted-foreground text-sm",e),...n})}function rD({className:e,...n}){return o.jsx("div",{"data-slot":"card-content",className:We("px-6",e),...n})}function oD({className:e,...n}){return o.jsx("div",{"data-slot":"card-footer",className:We("flex items-center px-6 [.border-t]:pt-6",e),...n})}const Cr=[{id:"foundry-weather-agent",name:"Azure AI Weather Agent",description:"Weather agent using Azure AI Agent (Foundry) with Azure CLI authentication",type:"agent",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/foundry_agent/agent.py",tags:["azure-ai","foundry","tools"],author:"Microsoft",difficulty:"beginner",features:["Azure AI Agent integration","Azure CLI authentication","Mock weather tools"],requiredEnvVars:[{name:"FOUNDRY_PROJECT_ENDPOINT",description:"Azure AI Foundry project endpoint URL",required:!0,example:"https://your-project.api.azureml.ms"},{name:"FOUNDRY_MODEL",description:"Name of the deployed model in Azure AI Foundry",required:!0,example:"gpt-4o"}]},{id:"weather-agent-azure",name:"Azure OpenAI Weather Agent",description:"Weather agent using Azure OpenAI with API key authentication",type:"agent",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/weather_agent_azure/agent.py",tags:["azure","openai","tools"],author:"Microsoft",difficulty:"beginner",features:["Azure OpenAI integration","API key authentication","Function calling","Mock weather tools"],requiredEnvVars:[{name:"AZURE_OPENAI_API_KEY",description:"Azure OpenAI API key",required:!0},{name:"AZURE_OPENAI_MODEL",description:"Name of the deployed model in Azure OpenAI",required:!0,example:"gpt-4o"},{name:"AZURE_OPENAI_ENDPOINT",description:"Azure OpenAI endpoint URL",required:!0,example:"https://your-resource.openai.azure.com"}]},{id:"spam-workflow",name:"Spam Detection Workflow",description:"5-step workflow demonstrating email spam detection with branching logic",type:"workflow",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/spam_workflow/workflow.py",tags:["workflow","branching","multi-step"],author:"Microsoft",difficulty:"beginner",features:["Sequential execution","Conditional branching","Mock spam detection"]},{id:"fanout-workflow",name:"Complex Fan-In/Fan-Out Workflow",description:"Advanced data processing workflow with parallel validation, transformation, and quality assurance stages",type:"workflow",url:"https://raw.githubusercontent.com/microsoft/agent-framework/main/python/samples/02-agents/devui/fanout_workflow/workflow.py",tags:["workflow","fan-out","fan-in","parallel"],author:"Microsoft",difficulty:"advanced",features:["Fan-out pattern","Parallel execution","Complex state management","Multi-stage processing"]}];Cr.filter(e=>e.type==="agent"),Cr.filter(e=>e.type==="workflow"),Cr.filter(e=>e.difficulty==="beginner"),Cr.filter(e=>e.difficulty==="intermediate"),Cr.filter(e=>e.difficulty==="advanced");const aD=e=>{switch(e){case"beginner":return"bg-green-100 text-green-700 border-green-200";case"intermediate":return"bg-yellow-100 text-yellow-700 border-yellow-200";case"advanced":return"bg-red-100 text-red-700 border-red-200";default:return"bg-gray-100 text-gray-700 border-gray-200"}},j2=w.forwardRef(({className:e,...n},r)=>o.jsx("div",{ref:r,role:"alert",className:We("relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",e),...n}));j2.displayName="Alert";const S2=w.forwardRef(({className:e,...n},r)=>o.jsx("h5",{ref:r,className:We("mb-1 font-medium leading-none tracking-tight",e),...n}));S2.displayName="AlertTitle";const _2=w.forwardRef(({className:e,...n},r)=>o.jsx("div",{ref:r,className:We("text-sm [&_p]:leading-relaxed",e),...n}));_2.displayName="AlertDescription";function E2({children:e,copyable:n=!1}){const[r,a]=w.useState(!1),l=()=>{navigator.clipboard.writeText(e),a(!0),setTimeout(()=>a(!1),2e3)};return o.jsxs("div",{className:"relative",children:[o.jsx("pre",{className:"bg-muted p-3 rounded-md text-sm overflow-x-auto font-mono",children:o.jsx("code",{children:e})}),n&&o.jsx(Le,{variant:"ghost",size:"sm",className:"absolute top-2 right-2 h-6 w-6 p-0",onClick:l,children:r?o.jsx(jo,{className:"h-3 w-3"}):o.jsx(uo,{className:"h-3 w-3"})})]})}function iu({number:e,title:n,description:r,code:a,action:l,copyable:c=!1}){return o.jsxs("div",{className:"flex gap-4",children:[o.jsx("div",{className:"flex-shrink-0",children:o.jsx("div",{className:"flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground font-semibold",children:e})}),o.jsxs("div",{className:"flex-1 space-y-2",children:[o.jsx("h4",{className:"font-semibold",children:n}),r&&o.jsx("p",{className:"text-sm text-muted-foreground",children:r}),a&&o.jsx(E2,{copyable:c,children:a}),l&&o.jsx("div",{children:l})]})]})}function iD({sample:e,open:n,onOpenChange:r}){const a=e.requiredEnvVars&&e.requiredEnvVars.length>0,l=a?0:-1;return o.jsx(Ir,{open:n,onOpenChange:r,children:o.jsxs(Lr,{className:"max-w-3xl",children:[o.jsxs($r,{className:"px-6 pt-6 pb-2",children:[o.jsxs(Pr,{children:["Setup: ",e.name]}),o.jsxs(OR,{children:["Follow these steps to run this sample ",e.type," locally"]})]}),o.jsx("div",{className:"px-6 pb-6",children:o.jsx(Wn,{className:"h-[500px]",children:o.jsxs("div",{className:"space-y-6 pr-4",children:[o.jsx(iu,{number:1,title:"Download the sample file",action:o.jsx(Le,{asChild:!0,size:"sm",children:o.jsxs("a",{href:e.url,download:`${e.id}.py`,target:"_blank",rel:"noopener noreferrer",children:[o.jsx(Pu,{className:"h-4 w-4 mr-2"}),"Download ",e.id,".py"]})})}),o.jsx(iu,{number:2,title:"Create a project folder",description:"Create a dedicated folder for this sample and move the downloaded file there:",code:`mkdir -p ~/my-agents/${e.id} mv ~/Downloads/${e.id}.py ~/my-agents/${e.id}/`,copyable:!0}),a&&o.jsx(iu,{number:3,title:"Set up environment variables",description:"Create a .env file in the project folder with these required variables:",code:e.requiredEnvVars.map(c=>`${c.name}=${c.example||"your-value-here"} # ${c.description}`).join(` diff --git a/python/packages/devui/dev.md b/python/packages/devui/dev.md index 899383e3b1..7c5e544c8e 100644 --- a/python/packages/devui/dev.md +++ b/python/packages/devui/dev.md @@ -37,7 +37,7 @@ OPENAI_CHAT_MODEL="gpt-4o-mini" # Or for Azure OpenAI AZURE_OPENAI_ENDPOINT="your-endpoint" -AZURE_OPENAI_DEPLOYMENT_NAME="your-deployment-name" +AZURE_OPENAI_MODEL="your-deployment-name" ``` ## 4. Test DevUI diff --git a/python/packages/devui/frontend/src/components/layout/deployment-modal.tsx b/python/packages/devui/frontend/src/components/layout/deployment-modal.tsx index f33351185f..ae1eddc235 100644 --- a/python/packages/devui/frontend/src/components/layout/deployment-modal.tsx +++ b/python/packages/devui/frontend/src/components/layout/deployment-modal.tsx @@ -247,7 +247,7 @@ services: # Or Azure OpenAI - AZURE_OPENAI_API_KEY=\${AZURE_OPENAI_API_KEY} - AZURE_OPENAI_ENDPOINT=\${AZURE_OPENAI_ENDPOINT} - - AZURE_OPENAI_DEPLOYMENT_NAME=\${AZURE_OPENAI_DEPLOYMENT_NAME} + - AZURE_OPENAI_MODEL=\${AZURE_OPENAI_MODEL} # Optional: Enable instrumentation - ENABLE_INSTRUMENTATION=\${ENABLE_INSTRUMENTATION:-false} ports: diff --git a/python/packages/devui/frontend/src/data/gallery/sample-entities.ts b/python/packages/devui/frontend/src/data/gallery/sample-entities.ts index d33e02ad7e..9509562dfc 100644 --- a/python/packages/devui/frontend/src/data/gallery/sample-entities.ts +++ b/python/packages/devui/frontend/src/data/gallery/sample-entities.ts @@ -78,7 +78,7 @@ export const SAMPLE_ENTITIES: SampleEntity[] = [ required: true, }, { - name: "AZURE_OPENAI_DEPLOYMENT_NAME", + name: "AZURE_OPENAI_MODEL", description: "Name of the deployed model in Azure OpenAI", required: true, example: "gpt-4o", diff --git a/python/packages/devui/tests/devui/test_server.py b/python/packages/devui/tests/devui/test_server.py index 8fbc127946..3f1945be3a 100644 --- a/python/packages/devui/tests/devui/test_server.py +++ b/python/packages/devui/tests/devui/test_server.py @@ -151,7 +151,7 @@ async def test_credential_cleanup() -> None: # Create mock chat client with credential mock_client = Mock() mock_client.async_credential = mock_credential - mock_client.model_id = "test-model" + mock_client.model = "test-model" mock_client.function_invocation_configuration = None # Create agent with mock client @@ -184,7 +184,7 @@ async def test_credential_cleanup_error_handling() -> None: # Create mock chat client with credential mock_client = Mock() mock_client.async_credential = mock_credential - mock_client.model_id = "test-model" + mock_client.model = "test-model" mock_client.function_invocation_configuration = None # Create agent with mock client @@ -219,7 +219,7 @@ async def test_multiple_credential_attributes() -> None: mock_client = Mock() mock_client.credential = mock_cred1 mock_client.async_credential = mock_cred2 - mock_client.model_id = "test-model" + mock_client.model = "test-model" mock_client.function_invocation_configuration = None # Create agent with mock client diff --git a/python/packages/durabletask/tests/integration_tests/.env.example b/python/packages/durabletask/tests/integration_tests/.env.example index f86f2382db..1944e8999c 100644 --- a/python/packages/durabletask/tests/integration_tests/.env.example +++ b/python/packages/durabletask/tests/integration_tests/.env.example @@ -1,6 +1,6 @@ # Azure OpenAI Configuration AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=your-deployment-name +AZURE_OPENAI_MODEL=your-deployment-name # Optional: Use Azure CLI authentication if not provided # AZURE_OPENAI_API_KEY=your-api-key diff --git a/python/packages/durabletask/tests/integration_tests/README.md b/python/packages/durabletask/tests/integration_tests/README.md index 5cce6712e4..704458a492 100644 --- a/python/packages/durabletask/tests/integration_tests/README.md +++ b/python/packages/durabletask/tests/integration_tests/README.md @@ -14,7 +14,7 @@ cp .env.example .env Required variables: - `AZURE_OPENAI_ENDPOINT` -- `AZURE_OPENAI_DEPLOYMENT_NAME` +- `AZURE_OPENAI_MODEL` - `AZURE_OPENAI_API_KEY` (optional if using Azure CLI authentication) - `ENDPOINT` (default: http://localhost:8080) - `TASKHUB` (default: default) @@ -97,7 +97,7 @@ If you see "DTS emulator is not available": If you see authentication or deployment errors: - Verify your `AZURE_OPENAI_ENDPOINT` is correct -- Confirm `AZURE_OPENAI_DEPLOYMENT_NAME` matches your deployment +- Confirm `AZURE_OPENAI_MODEL` matches your deployment - If using API key, check `AZURE_OPENAI_API_KEY` is valid - If using Azure CLI, ensure you're logged in: `az login` diff --git a/python/packages/durabletask/tests/integration_tests/conftest.py b/python/packages/durabletask/tests/integration_tests/conftest.py index 94fce45109..65202e2907 100644 --- a/python/packages/durabletask/tests/integration_tests/conftest.py +++ b/python/packages/durabletask/tests/integration_tests/conftest.py @@ -291,7 +291,7 @@ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item """Skip tests based on markers and environment availability.""" foundry_vars = ["FOUNDRY_PROJECT_ENDPOINT", "FOUNDRY_MODEL"] foundry_available = all(os.getenv(var) for var in foundry_vars) - azure_openai_vars = ["AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_DEPLOYMENT_NAME"] + azure_openai_vars = ["AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_MODEL"] azure_openai_available = all(os.getenv(var) for var in azure_openai_vars) skip_foundry = pytest.mark.skip(reason=f"Missing required environment variables: {', '.join(foundry_vars)}") skip_azure_openai = pytest.mark.skip( @@ -348,7 +348,7 @@ def check_sample_env(request: pytest.FixtureRequest) -> None: sample_name = cast(str, sample_marker.args[0]) # type: ignore[union-attr] if sample_name == "06_multi_agent_orchestration_conditionals": - required_vars = ["AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_DEPLOYMENT_NAME"] + required_vars = ["AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_MODEL"] else: required_vars = ["FOUNDRY_PROJECT_ENDPOINT", "FOUNDRY_MODEL"] missing = [var for var in required_vars if not os.getenv(var)] diff --git a/python/packages/foundry/agent_framework_foundry/_chat_client.py b/python/packages/foundry/agent_framework_foundry/_chat_client.py index 4634ec8524..b8ae5ce398 100644 --- a/python/packages/foundry/agent_framework_foundry/_chat_client.py +++ b/python/packages/foundry/agent_framework_foundry/_chat_client.py @@ -477,15 +477,14 @@ class FoundryChatClient( # type: ignore[misc] - ``FOUNDRY_MODEL`` to provide the Foundry model deployment name. Keyword Args: - project_endpoint: The Foundry project endpoint URL. - Can also be set via environment variable ``FOUNDRY_PROJECT_ENDPOINT``. - project_client: An existing AIProjectClient to use. - model: The model deployment name. - Can also be set via environment variable ``FOUNDRY_MODEL``. - model_id: Deprecated alias for ``model``. - credential: Azure credential or token provider for authentication. - allow_preview: Enables preview opt-in on internally-created AIProjectClient. - env_file_path: Path to .env file for settings. + project_endpoint: The Foundry project endpoint URL. + Can also be set via environment variable ``FOUNDRY_PROJECT_ENDPOINT``. + project_client: An existing AIProjectClient to use. + model: The model deployment name. + Can also be set via environment variable ``FOUNDRY_MODEL``. + credential: Azure credential or token provider for authentication. + allow_preview: Enables preview opt-in on internally-created AIProjectClient. + env_file_path: Path to .env file for settings. env_file_encoding: Encoding for .env file. instruction_role: The role to use for 'instruction' messages. middleware: Optional sequence of middleware. diff --git a/python/packages/foundry_local/AGENTS.md b/python/packages/foundry_local/AGENTS.md index 5957b51565..91f14ed230 100644 --- a/python/packages/foundry_local/AGENTS.md +++ b/python/packages/foundry_local/AGENTS.md @@ -13,7 +13,7 @@ Integration with Azure AI Foundry Local for local model inference. ```python from agent_framework.foundry import FoundryLocalClient -client = FoundryLocalClient(model_id="your-local-model") +client = FoundryLocalClient(model="your-local-model") response = await client.get_response("Hello") ``` diff --git a/python/packages/foundry_local/agent_framework_foundry_local/_foundry_local_client.py b/python/packages/foundry_local/agent_framework_foundry_local/_foundry_local_client.py index 5b0e15f2a2..f51a77c054 100644 --- a/python/packages/foundry_local/agent_framework_foundry_local/_foundry_local_client.py +++ b/python/packages/foundry_local/agent_framework_foundry_local/_foundry_local_client.py @@ -23,7 +23,7 @@ from agent_framework._settings import load_settings from agent_framework.observability import ChatTelemetryLayer from agent_framework_openai._chat_completion_client import RawOpenAIChatCompletionClient from foundry_local import FoundryLocalManager -from foundry_local.models import DeviceType +from foundry_local.models import DeviceType, FoundryModelInfo from openai import AsyncOpenAI from pydantic import BaseModel @@ -60,7 +60,7 @@ class FoundryLocalChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModel Keys: # Inherited from ChatOptions (supported via OpenAI-compatible API): - model_id: The model identifier or alias (e.g., 'phi-4-mini'). + model: The model identifier or alias (e.g., 'phi-4-mini'). temperature: Sampling temperature (0-2). top_p: Nucleus sampling parameter. max_tokens: Maximum tokens to generate. @@ -104,11 +104,6 @@ class FoundryLocalChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModel """Not applicable for local inference.""" -FOUNDRY_LOCAL_OPTION_TRANSLATIONS: dict[str, str] = { - "model_id": "model", -} -"""Maps ChatOptions keys to OpenAI API parameter names (for compatibility).""" - FoundryLocalChatOptionsT = TypeVar( "FoundryLocalChatOptionsT", bound=TypedDict, # type: ignore[valid-type] @@ -295,8 +290,8 @@ class FoundryLocalClient( # will take a long time as the model is loaded then. # Alternatively, you could call the `download_model` and `load_model` methods # on the `manager` property manually. - client.manager.download_model(alias_or_model_id="phi-4-mini", device=DeviceType.CPU) - client.manager.load_model(alias_or_model_id="phi-4-mini", device=DeviceType.CPU) + client.manager.download_model("phi-4-mini", device=DeviceType.CPU) + client.manager.load_model("phi-4-mini", device=DeviceType.CPU) # You can also use the CLI: `foundry model load phi-4-mini --device Auto` @@ -328,8 +323,8 @@ class FoundryLocalClient( model_setting: str = settings["model"] # type: ignore[assignment] # pyright: ignore[reportTypedDictNotRequiredAccess] manager = FoundryLocalManager(bootstrap=bootstrap, timeout=timeout) - model_info = manager.get_model_info( - alias_or_model_id=model_setting, + model_info: FoundryModelInfo | None = manager.get_model_info( + model_setting, device=device, ) if model_info is None: @@ -340,8 +335,8 @@ class FoundryLocalClient( ) raise ValueError(message) if prepare_model: - manager.download_model(alias_or_model_id=model_info.id, device=device) - manager.load_model(alias_or_model_id=model_info.id, device=device) + manager.download_model(model_info.id, device=device) + manager.load_model(model_info.id, device=device) super().__init__( model=model_info.id, diff --git a/python/packages/foundry_local/tests/test_foundry_local_client.py b/python/packages/foundry_local/tests/test_foundry_local_client.py index 02b42f22a6..43b2918ca0 100644 --- a/python/packages/foundry_local/tests/test_foundry_local_client.py +++ b/python/packages/foundry_local/tests/test_foundry_local_client.py @@ -34,7 +34,7 @@ def test_foundry_local_settings_init_with_explicit_values() -> None: @pytest.mark.parametrize("exclude_list", [["FOUNDRY_LOCAL_MODEL"]], indirect=True) def test_foundry_local_settings_missing_model(foundry_local_unit_test_env: dict[str, str]) -> None: - """Test FoundryLocalSettings when model_id is missing raises error.""" + """Test FoundryLocalSettings when model is missing raises error.""" with pytest.raises(SettingNotFoundError, match="Required setting 'model'"): load_settings( FoundryLocalSettings, @@ -157,15 +157,15 @@ def test_foundry_local_client_init_with_device(mock_foundry_local_manager: Magic FoundryLocalClient(model="test-model-id", device=DeviceType.CPU) mock_foundry_local_manager.get_model_info.assert_called_once_with( - alias_or_model_id="test-model-id", + "test-model-id", device=DeviceType.CPU, ) mock_foundry_local_manager.download_model.assert_called_once_with( - alias_or_model_id="test-model-id", + "test-model-id", device=DeviceType.CPU, ) mock_foundry_local_manager.load_model.assert_called_once_with( - alias_or_model_id="test-model-id", + "test-model-id", device=DeviceType.CPU, ) @@ -207,10 +207,10 @@ def test_foundry_local_client_init_calls_download_and_load(mock_foundry_local_ma FoundryLocalClient(model="test-model-id") mock_foundry_local_manager.download_model.assert_called_once_with( - alias_or_model_id="test-model-id", + "test-model-id", device=None, ) mock_foundry_local_manager.load_model.assert_called_once_with( - alias_or_model_id="test-model-id", + "test-model-id", device=None, ) diff --git a/python/packages/lab/lightning/README.md b/python/packages/lab/lightning/README.md index e9fd3ec91d..75c585bdaa 100644 --- a/python/packages/lab/lightning/README.md +++ b/python/packages/lab/lightning/README.md @@ -51,7 +51,7 @@ async def math_agent(task: TaskType, llm: LLM) -> float: MCPStdioTool(name="calculator", command="uvx", args=["mcp-server-calculator"]) as mcp_server, Agent( client=OpenAIChatClient( - model_id=llm.model, + model=llm.model, api_key="your-api-key", base_url=llm.endpoint, ), diff --git a/python/packages/lab/lightning/samples/train_math_agent.py b/python/packages/lab/lightning/samples/train_math_agent.py index 98e79484bc..a58e7886d1 100644 --- a/python/packages/lab/lightning/samples/train_math_agent.py +++ b/python/packages/lab/lightning/samples/train_math_agent.py @@ -169,7 +169,7 @@ async def math_agent(task: MathProblem, llm: LLM) -> float: MCPStdioTool(name="calculator", command="uvx", args=["mcp-server-calculator"]) as mcp_server, Agent( client=OpenAIChatClient( - model_id=llm.model, # This is the model being trained + model=llm.model, # This is the model being trained api_key=os.getenv("OPENAI_API_KEY") or "dummy", # Can be dummy when connecting to training LLM base_url=llm.endpoint, # vLLM server endpoint provided by agent-lightning ), diff --git a/python/packages/lab/lightning/samples/train_tau2_agent.py b/python/packages/lab/lightning/samples/train_tau2_agent.py index e9514b6f77..ea07ddc7e8 100644 --- a/python/packages/lab/lightning/samples/train_tau2_agent.py +++ b/python/packages/lab/lightning/samples/train_tau2_agent.py @@ -106,14 +106,14 @@ class Tau2Agent(LitAgent): assistant_chat_client = OpenAIChatClient( base_url=llm.endpoint, # vLLM endpoint for the model being trained api_key=openai_api_key, - model_id=llm.model, # Model ID being trained + model=llm.model, # Model ID being trained ) # User simulator: uses a fixed, capable model for consistent simulation user_simulator_chat_client = OpenAIChatClient( base_url=openai_base_url, # External API endpoint api_key=openai_api_key, - model_id="gpt-4.1", # Fixed model for user simulator + model="gpt-4.1", # Fixed model for user simulator ) try: diff --git a/python/packages/lab/tau2/README.md b/python/packages/lab/tau2/README.md index 083fd05a9d..0e6b5ea735 100644 --- a/python/packages/lab/tau2/README.md +++ b/python/packages/lab/tau2/README.md @@ -67,12 +67,12 @@ async def run_single_task(): assistant_client = OpenAIChatClient( base_url="https://api.openai.com/v1", api_key="your-api-key", - model_id="gpt-4o" + model="gpt-4o" ) user_client = OpenAIChatClient( base_url="https://api.openai.com/v1", api_key="your-api-key", - model_id="gpt-4o-mini" + model="gpt-4o-mini" ) # Get a task and run it diff --git a/python/packages/lab/tau2/samples/run_benchmark.py b/python/packages/lab/tau2/samples/run_benchmark.py index 5c2ed14d5e..5d11226bb1 100644 --- a/python/packages/lab/tau2/samples/run_benchmark.py +++ b/python/packages/lab/tau2/samples/run_benchmark.py @@ -96,14 +96,14 @@ async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: st assistant_chat_client = OpenAIChatClient( base_url=openai_base_url, api_key=openai_api_key, - model_id=assistant_model, + model=assistant_model, ) # User simulator: simulates realistic customer behavior and requests user_simulator_chat_client = OpenAIChatClient( base_url=openai_base_url, api_key=openai_api_key, - model_id=user_model, + model=user_model, ) # STEP 4: Filter task set for debug mode @@ -133,8 +133,8 @@ async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: st # Initialize result structure for this task result: dict[str, Any] = { "config": { - "assistant": assistant_chat_client.model_id, - "user": user_simulator_chat_client.model_id, + "assistant": assistant_chat_client.model, + "user": user_simulator_chat_client.model, }, "task": task, } @@ -183,8 +183,8 @@ async def run_benchmark(assistant_model: str, user_model: str, debug_task_id: st # Initialize result structure for this task result: dict[str, Any] = { "config": { - "assistant": assistant_chat_client.model_id, - "user": user_simulator_chat_client.model_id, + "assistant": assistant_chat_client.model, + "user": user_simulator_chat_client.model, }, "task": task, } diff --git a/python/packages/ollama/AGENTS.md b/python/packages/ollama/AGENTS.md index 3a4aa0f928..be0c7af951 100644 --- a/python/packages/ollama/AGENTS.md +++ b/python/packages/ollama/AGENTS.md @@ -13,7 +13,7 @@ Integration with Ollama for local LLM inference. ```python from agent_framework.ollama import OllamaChatClient -client = OllamaChatClient(model_id="llama3.2") +client = OllamaChatClient(model="llama3.2") response = await client.get_response("Hello") ``` diff --git a/python/packages/ollama/agent_framework_ollama/_chat_client.py b/python/packages/ollama/agent_framework_ollama/_chat_client.py index 0c7f232797..cce4c14332 100644 --- a/python/packages/ollama/agent_framework_ollama/_chat_client.py +++ b/python/packages/ollama/agent_framework_ollama/_chat_client.py @@ -77,7 +77,7 @@ class OllamaChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], to Keys: # Inherited from ChatOptions (mapped to Ollama options): - model_id: The model name, translates to ``model`` in Ollama API. + model: The model name, translates to ``model`` in Ollama API. temperature: Sampling temperature, translates to ``options.temperature``. top_p: Nucleus sampling, translates to ``options.top_p``. max_tokens: Maximum tokens to generate, translates to ``options.num_predict``. @@ -229,7 +229,6 @@ class OllamaChatOptions(ChatOptions[ResponseModelT], Generic[ResponseModelT], to OLLAMA_OPTION_TRANSLATIONS: dict[str, str] = { - "model_id": "model", "response_format": "format", } """Maps ChatOptions keys to Ollama API parameter names.""" @@ -278,7 +277,7 @@ class OllamaSettings(TypedDict, total=False): """Ollama settings.""" host: str | None - model_id: str | None + model: str | None logger = logging.getLogger("agent_framework.ollama") @@ -299,7 +298,7 @@ class OllamaChatClient( *, host: str | None = None, client: AsyncClient | None = None, - model_id: str | None = None, + model: str | None = None, additional_properties: dict[str, Any] | None = None, middleware: Sequence[ChatAndFunctionMiddlewareTypes] | None = None, function_invocation_configuration: FunctionInvocationConfiguration | None = None, @@ -312,7 +311,7 @@ class OllamaChatClient( host: Ollama server URL, if none `http://localhost:11434` is used. Can be set via the OLLAMA_HOST env variable. client: An optional Ollama Client instance. If not provided, a new instance will be created. - model_id: The Ollama chat model ID to use. Can be set via the OLLAMA_MODEL_ID env variable. + model: The Ollama chat model to use. Can be set via the OLLAMA_MODEL env variable. additional_properties: Additional properties stored on the client instance. middleware: Optional middleware to apply to the client. function_invocation_configuration: Optional function invocation configuration override. @@ -322,14 +321,14 @@ class OllamaChatClient( ollama_settings = load_settings( OllamaSettings, env_prefix="OLLAMA_", - required_fields=["model_id"], + required_fields=["model"], host=host, - model_id=model_id, + model=model, env_file_encoding=env_file_encoding, env_file_path=env_file_path, ) - self.model_id = ollama_settings["model_id"] # type: ignore[assignment, reportTypedDictNotRequiredAccess] + self.model = ollama_settings["model"] # type: ignore[assignment, reportTypedDictNotRequiredAccess] # we can just pass in None for the host, the default is set by the Ollama package. self.client = client or AsyncClient(host=ollama_settings.get("host")) # Save Host URL for serialization with to_dict() @@ -411,7 +410,7 @@ class OllamaChatClient( translated_key = OLLAMA_MODEL_OPTION_TRANSLATIONS.get(key, key) model_options[translated_key] = value else: - # Apply top-level translations (e.g., model_id -> model) + # Apply top-level translations (e.g., response_format -> format) translated_key = OLLAMA_OPTION_TRANSLATIONS.get(key, key) run_options[translated_key] = value @@ -425,11 +424,11 @@ class OllamaChatClient( if "messages" not in run_options: raise ChatClientInvalidRequestException("Messages are required for chat completions") - # model id + # model if not run_options.get("model"): - if not self.model_id: - raise ValueError("model_id must be a non-empty string") - run_options["model"] = self.model_id + if not self.model: + raise ValueError("model must be a non-empty string") + run_options["model"] = self.model # tools tools = options.get("tools") @@ -533,7 +532,7 @@ class OllamaChatClient( return ChatResponseUpdate( contents=contents, role="assistant", - model_id=response.model, + model=response.model, created_at=response.created_at, ) @@ -542,7 +541,7 @@ class OllamaChatClient( return ChatResponse( messages=[Message(role="assistant", contents=contents)], - model_id=response.model, + model=response.model, created_at=response.created_at, usage_details=UsageDetails( input_token_count=response.prompt_eval_count, diff --git a/python/packages/ollama/agent_framework_ollama/_embedding_client.py b/python/packages/ollama/agent_framework_ollama/_embedding_client.py index 8e0508c708..e921e6172a 100644 --- a/python/packages/ollama/agent_framework_ollama/_embedding_client.py +++ b/python/packages/ollama/agent_framework_ollama/_embedding_client.py @@ -38,7 +38,7 @@ class OllamaEmbeddingOptions(EmbeddingGenerationOptions, total=False): from agent_framework_ollama import OllamaEmbeddingOptions options: OllamaEmbeddingOptions = { - "model_id": "nomic-embed-text", + "model": "nomic-embed-text", "dimensions": 768, "truncate": True, } @@ -67,7 +67,7 @@ class OllamaEmbeddingSettings(TypedDict, total=False): """Ollama embedding settings.""" host: str | None - embedding_model_id: str | None + embedding_model: str | None class RawOllamaEmbeddingClient( @@ -77,8 +77,8 @@ class RawOllamaEmbeddingClient( """Raw Ollama embedding client without telemetry. Keyword Args: - model_id: The Ollama embedding model ID (e.g. "nomic-embed-text"). - Can also be set via environment variable OLLAMA_EMBEDDING_MODEL_ID. + model: The Ollama embedding model (e.g. "nomic-embed-text"). + Can also be set via environment variable OLLAMA_EMBEDDING_MODEL. host: Ollama server URL. Defaults to http://localhost:11434. Can also be set via environment variable OLLAMA_HOST. client: Optional pre-configured Ollama AsyncClient. @@ -89,7 +89,7 @@ class RawOllamaEmbeddingClient( def __init__( self, *, - model_id: str | None = None, + model: str | None = None, host: str | None = None, client: AsyncClient | None = None, additional_properties: dict[str, Any] | None = None, @@ -100,14 +100,14 @@ class RawOllamaEmbeddingClient( ollama_settings = load_settings( OllamaEmbeddingSettings, env_prefix="OLLAMA_", - required_fields=["embedding_model_id"], + required_fields=["embedding_model"], host=host, - embedding_model_id=model_id, + embedding_model=model, env_file_path=env_file_path, env_file_encoding=env_file_encoding, ) - self.model_id = ollama_settings["embedding_model_id"] # type: ignore[assignment,reportTypedDictNotRequiredAccess] + self.model = ollama_settings["embedding_model"] # type: ignore[assignment,reportTypedDictNotRequiredAccess] self.client = client or AsyncClient(host=ollama_settings.get("host")) self.host = str(self.client._client.base_url) # type: ignore[reportUnknownMemberType,reportPrivateUsage,reportUnknownArgumentType] super().__init__(additional_properties=additional_properties) @@ -132,15 +132,15 @@ class RawOllamaEmbeddingClient( Generated embeddings with usage metadata. Raises: - ValueError: If model_id is not provided or values is empty. + ValueError: If model is not provided or values is empty. """ if not values: return GeneratedEmbeddings([], options=options) opts: dict[str, Any] = options or {} # type: ignore - model = opts.get("model_id") or self.model_id + model = opts.get("model") or self.model if not model: - raise ValueError("model_id is required") + raise ValueError("model is required") kwargs: dict[str, Any] = {"model": model, "input": list(values)} if (truncate := opts.get("truncate")) is not None: @@ -156,7 +156,7 @@ class RawOllamaEmbeddingClient( Embedding( vector=list(emb), dimensions=len(emb), - model_id=response.get("model") or model, # type: ignore[assignment] + model=response.get("model") or model, # type: ignore[assignment] ) for emb in response.get("embeddings", []) ] @@ -177,8 +177,8 @@ class OllamaEmbeddingClient( """Ollama embedding client with telemetry support. Keyword Args: - model_id: The Ollama embedding model ID (e.g. "nomic-embed-text"). - Can also be set via environment variable OLLAMA_EMBEDDING_MODEL_ID. + model: The Ollama embedding model (e.g. "nomic-embed-text"). + Can also be set via environment variable OLLAMA_EMBEDDING_MODEL. host: Ollama server URL. Defaults to http://localhost:11434. Can also be set via environment variable OLLAMA_HOST. client: Optional pre-configured Ollama AsyncClient. @@ -191,12 +191,12 @@ class OllamaEmbeddingClient( from agent_framework_ollama import OllamaEmbeddingClient # Using environment variables - # Set OLLAMA_EMBEDDING_MODEL_ID=nomic-embed-text + # Set OLLAMA_EMBEDDING_MODEL=nomic-embed-text client = OllamaEmbeddingClient() # Or passing parameters directly client = OllamaEmbeddingClient( - model_id="nomic-embed-text", + model="nomic-embed-text", host="http://localhost:11434", ) @@ -210,7 +210,7 @@ class OllamaEmbeddingClient( def __init__( self, *, - model_id: str | None = None, + model: str | None = None, host: str | None = None, client: AsyncClient | None = None, otel_provider_name: str | None = None, @@ -220,7 +220,7 @@ class OllamaEmbeddingClient( ) -> None: """Initialize an Ollama embedding client.""" super().__init__( - model_id=model_id, + model=model, host=host, client=client, additional_properties=additional_properties, diff --git a/python/packages/ollama/tests/ollama/test_ollama_embedding_client.py b/python/packages/ollama/tests/ollama/test_ollama_embedding_client.py index c585f9c481..63dffeb7c1 100644 --- a/python/packages/ollama/tests/ollama/test_ollama_embedding_client.py +++ b/python/packages/ollama/tests/ollama/test_ollama_embedding_client.py @@ -13,11 +13,11 @@ from agent_framework_ollama import OllamaEmbeddingClient, OllamaEmbeddingOptions def test_ollama_embedding_construction(monkeypatch: pytest.MonkeyPatch) -> None: """Test construction with explicit parameters.""" - monkeypatch.setenv("OLLAMA_EMBEDDING_MODEL_ID", "nomic-embed-text") + monkeypatch.setenv("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text") with patch("agent_framework_ollama._embedding_client.AsyncClient") as mock_client_cls: mock_client_cls.return_value = MagicMock() client = OllamaEmbeddingClient() - assert client.model_id == "nomic-embed-text" + assert client.model == "nomic-embed-text" def test_ollama_embedding_construction_with_params() -> None: @@ -25,16 +25,16 @@ def test_ollama_embedding_construction_with_params() -> None: with patch("agent_framework_ollama._embedding_client.AsyncClient") as mock_client_cls: mock_client_cls.return_value = MagicMock() client = OllamaEmbeddingClient( - model_id="nomic-embed-text", + model="nomic-embed-text", host="http://localhost:11434", ) - assert client.model_id == "nomic-embed-text" + assert client.model == "nomic-embed-text" def test_ollama_embedding_construction_missing_model_raises(monkeypatch: pytest.MonkeyPatch) -> None: - """Test that missing model_id raises an error.""" - monkeypatch.delenv("OLLAMA_EMBEDDING_MODEL_ID", raising=False) - monkeypatch.delenv("OLLAMA_MODEL_ID", raising=False) + """Test that missing model raises an error.""" + monkeypatch.delenv("OLLAMA_EMBEDDING_MODEL", raising=False) + monkeypatch.delenv("OLLAMA_MODEL", raising=False) from agent_framework.exceptions import SettingNotFoundError with pytest.raises(SettingNotFoundError): @@ -54,14 +54,14 @@ async def test_ollama_embedding_get_embeddings() -> None: mock_client.embed = AsyncMock(return_value=mock_response) mock_client_cls.return_value = mock_client - client = OllamaEmbeddingClient(model_id="nomic-embed-text") + client = OllamaEmbeddingClient(model="nomic-embed-text") result = await client.get_embeddings(["hello", "world"]) assert isinstance(result, GeneratedEmbeddings) assert len(result) == 2 assert result[0].vector == [0.1, 0.2, 0.3] assert result[1].vector == [0.4, 0.5, 0.6] - assert result[0].model_id == "nomic-embed-text" + assert result[0].model == "nomic-embed-text" assert result.usage == {"input_token_count": 10} mock_client.embed.assert_called_once_with( @@ -76,7 +76,7 @@ async def test_ollama_embedding_get_embeddings_empty_input() -> None: mock_client = MagicMock() mock_client_cls.return_value = mock_client - client = OllamaEmbeddingClient(model_id="nomic-embed-text") + client = OllamaEmbeddingClient(model="nomic-embed-text") result = await client.get_embeddings([]) assert isinstance(result, GeneratedEmbeddings) @@ -96,7 +96,7 @@ async def test_ollama_embedding_get_embeddings_with_options() -> None: mock_client.embed = AsyncMock(return_value=mock_response) mock_client_cls.return_value = mock_client - client = OllamaEmbeddingClient(model_id="nomic-embed-text") + client = OllamaEmbeddingClient(model="nomic-embed-text") options: OllamaEmbeddingOptions = { "truncate": True, "dimensions": 512, @@ -113,22 +113,22 @@ async def test_ollama_embedding_get_embeddings_with_options() -> None: async def test_ollama_embedding_get_embeddings_no_model_raises() -> None: - """Test that missing model_id at call time raises ValueError.""" + """Test that missing model at call time raises ValueError.""" with patch("agent_framework_ollama._embedding_client.AsyncClient") as mock_client_cls: mock_client = MagicMock() mock_client_cls.return_value = mock_client - client = OllamaEmbeddingClient(model_id="nomic-embed-text") - client.model_id = None # type: ignore[assignment] + client = OllamaEmbeddingClient(model="nomic-embed-text") + client.model = None # type: ignore[assignment] - with pytest.raises(ValueError, match="model_id is required"): + with pytest.raises(ValueError, match="model is required"): await client.get_embeddings(["hello"]) # region: Integration Tests skip_if_ollama_embedding_integration_tests_disabled = pytest.mark.skipif( - os.getenv("OLLAMA_EMBEDDING_MODEL_ID", "") in ("", "test-model"), + os.getenv("OLLAMA_EMBEDDING_MODEL", "") in ("", "test-model"), reason="No real Ollama embedding model provided; skipping integration tests.", ) diff --git a/python/packages/ollama/tests/test_ollama_chat_client.py b/python/packages/ollama/tests/test_ollama_chat_client.py index 490bbc0a15..c4c66077e4 100644 --- a/python/packages/ollama/tests/test_ollama_chat_client.py +++ b/python/packages/ollama/tests/test_ollama_chat_client.py @@ -26,7 +26,7 @@ from agent_framework_ollama import OllamaChatClient # region Service Setup skip_if_azure_integration_tests_disabled = pytest.mark.skipif( - os.getenv("OLLAMA_MODEL_ID", "") in ("", "test-model"), + os.getenv("OLLAMA_MODEL", "") in ("", "test-model"), reason="No real Ollama chat model provided; skipping integration tests.", ) @@ -55,7 +55,7 @@ def ollama_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # if override_env_param_dict is None: override_env_param_dict = {} - env_vars = {"OLLAMA_HOST": "http://localhost:12345", "OLLAMA_MODEL_ID": "test"} + env_vars = {"OLLAMA_HOST": "http://localhost:12345", "OLLAMA_MODEL": "test"} env_vars.update(override_env_param_dict) # type: ignore @@ -156,7 +156,7 @@ def test_init(ollama_unit_test_env: dict[str, str]) -> None: assert ollama_chat_client.client is not None assert isinstance(ollama_chat_client.client, AsyncClient) - assert ollama_chat_client.model_id == ollama_unit_test_env["OLLAMA_MODEL_ID"] + assert ollama_chat_client.model == ollama_unit_test_env["OLLAMA_MODEL"] assert isinstance(ollama_chat_client, BaseChatClient) @@ -165,27 +165,27 @@ def test_init_client(ollama_unit_test_env: dict[str, str]) -> None: test_client = MagicMock(spec=AsyncClient) # Mock underlying HTTP client's base_url test_client._client = MagicMock() - test_client._client.base_url = ollama_unit_test_env["OLLAMA_MODEL_ID"] + test_client._client.base_url = ollama_unit_test_env["OLLAMA_MODEL"] ollama_chat_client = OllamaChatClient(client=test_client) assert ollama_chat_client.client is test_client - assert ollama_chat_client.model_id == ollama_unit_test_env["OLLAMA_MODEL_ID"] + assert ollama_chat_client.model == ollama_unit_test_env["OLLAMA_MODEL"] assert isinstance(ollama_chat_client, BaseChatClient) -@pytest.mark.parametrize("exclude_list", [["OLLAMA_MODEL_ID"]], indirect=True) +@pytest.mark.parametrize("exclude_list", [["OLLAMA_MODEL"]], indirect=True) def test_with_invalid_settings(ollama_unit_test_env: dict[str, str]) -> None: - with pytest.raises(SettingNotFoundError, match="Required setting 'model_id'"): + with pytest.raises(SettingNotFoundError, match="Required setting 'model'"): OllamaChatClient( host="http://localhost:12345", - model_id=None, + model=None, ) def test_serialize(ollama_unit_test_env: dict[str, str]) -> None: settings = { "host": ollama_unit_test_env["OLLAMA_HOST"], - "model_id": ollama_unit_test_env["OLLAMA_MODEL_ID"], + "model": ollama_unit_test_env["OLLAMA_MODEL"], } ollama_chat_client = OllamaChatClient.from_dict(settings) @@ -193,7 +193,7 @@ def test_serialize(ollama_unit_test_env: dict[str, str]) -> None: assert isinstance(serialized, dict) assert serialized["host"] == ollama_unit_test_env["OLLAMA_HOST"] - assert serialized["model_id"] == ollama_unit_test_env["OLLAMA_MODEL_ID"] + assert serialized["model"] == ollama_unit_test_env["OLLAMA_MODEL"] def test_chat_middleware(ollama_unit_test_env: dict[str, str]) -> None: @@ -225,7 +225,7 @@ def test_additional_properties(ollama_unit_test_env: dict[str, str]) -> None: async def test_empty_messages() -> None: ollama_chat_client = OllamaChatClient( host="http://localhost:12345", - model_id="test-model", + model="test-model", ) with pytest.raises(ChatClientInvalidRequestException): await ollama_chat_client.get_response(messages=[]) diff --git a/python/packages/openai/README.md b/python/packages/openai/README.md index a1847e4e44..17f1ee9597 100644 --- a/python/packages/openai/README.md +++ b/python/packages/openai/README.md @@ -56,16 +56,16 @@ These variables are used when the client is configured for Azure OpenAI: | `AZURE_OPENAI_BASE_URL` | Full Azure OpenAI base URL (`.../openai/v1`) | | `AZURE_OPENAI_API_KEY` | Azure OpenAI API key | | `AZURE_OPENAI_API_VERSION` | Azure OpenAI API version | -| `AZURE_OPENAI_DEPLOYMENT_NAME` | Generic fallback deployment | -| `AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME` | Preferred deployment for `OpenAIChatClient` | -| `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` | Preferred deployment for `OpenAIChatCompletionClient` | -| `AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME` | Preferred deployment for `OpenAIEmbeddingClient` | +| `AZURE_OPENAI_MODEL` | Generic fallback deployment | +| `AZURE_OPENAI_RESPONSES_MODEL` | Preferred deployment for `OpenAIChatClient` | +| `AZURE_OPENAI_CHAT_MODEL` | Preferred deployment for `OpenAIChatCompletionClient` | +| `AZURE_OPENAI_EMBEDDING_MODEL` | Preferred deployment for `OpenAIEmbeddingClient` | Deployment lookup order: -- `OpenAIChatClient`: `AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME` -> `AZURE_OPENAI_DEPLOYMENT_NAME` -- `OpenAIChatCompletionClient`: `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` -> `AZURE_OPENAI_DEPLOYMENT_NAME` -- `OpenAIEmbeddingClient`: `AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME` -> `AZURE_OPENAI_DEPLOYMENT_NAME` +- `OpenAIChatClient`: `AZURE_OPENAI_RESPONSES_MODEL` -> `AZURE_OPENAI_MODEL` +- `OpenAIChatCompletionClient`: `AZURE_OPENAI_CHAT_MODEL` -> `AZURE_OPENAI_MODEL` +- `OpenAIEmbeddingClient`: `AZURE_OPENAI_EMBEDDING_MODEL` -> `AZURE_OPENAI_MODEL` 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 diff --git a/python/packages/openai/agent_framework_openai/_chat_client.py b/python/packages/openai/agent_framework_openai/_chat_client.py index 30c88b0848..5f79126711 100644 --- a/python/packages/openai/agent_framework_openai/_chat_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_client.py @@ -331,8 +331,8 @@ class RawOpenAIChatClient( # type: ignore[misc] Keyword Args: model: Model identifier to use for the request. When not provided, the constructor - reads ``AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME``. + reads ``AZURE_OPENAI_RESPONSES_MODEL`` and then + ``AZURE_OPENAI_MODEL``. azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor reads ``AZURE_OPENAI_ENDPOINT``. credential: Azure credential or token provider for Entra auth. @@ -361,7 +361,6 @@ class RawOpenAIChatClient( # type: ignore[misc] self, model: str | None = None, *, - model_id: str | None = None, api_key: str | SecretString | Callable[[], str | Awaitable[str]] | None = None, credential: AzureCredentialTypes | AzureTokenProvider | None = None, org_id: str | None = None, @@ -382,9 +381,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`` for OpenAI, - or ``AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME`` for Azure. - model_id: Deprecated alias for ``model``. + or ``AZURE_OPENAI_RESPONSES_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, @@ -424,15 +421,9 @@ class RawOpenAIChatClient( # type: ignore[misc] OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_RESPONSES_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_DEPLOYMENT_NAME``, - ``AZURE_OPENAI_DEPLOYMENT_NAME``, and ``AZURE_OPENAI_API_VERSION``. + ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_RESPONSES_MODEL``, + ``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``. """ - if model_id is not None and model is None: - import warnings - - warnings.warn("model_id is deprecated, use model instead", DeprecationWarning, stacklevel=2) - model = model_id - settings, client, use_azure_client = load_openai_service_settings( model=model, api_key=api_key, @@ -447,12 +438,12 @@ class RawOpenAIChatClient( # type: ignore[misc] env_file_path=env_file_path, env_file_encoding=env_file_encoding, openai_model_fields=("responses_model", "model"), - azure_deployment_fields=("responses_deployment_name", "deployment_name"), + azure_model_fields=("responses_model", "model"), responses_mode=True, ) self.client = client - self.model: str = settings.get("model") or settings.get("deployment_name") or "" + self.model: str = settings.get("model") or "" # Store configuration for serialization self.org_id = settings.get("org_id") @@ -1178,7 +1169,6 @@ class RawOpenAIChatClient( # type: ignore[misc] # translations between options and Responses API translations = { - "model_id": "model", # backward compat: accept model_id in options "allow_multiple_tool_calls": "parallel_tool_calls", "conversation_id": "previous_response_id", "max_tokens": "max_output_tokens", @@ -2559,8 +2549,8 @@ class OpenAIChatClient( # type: ignore[misc] Keyword Args: model: Model identifier to use for the request. When not provided, the constructor - reads ``AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME``. + reads ``AZURE_OPENAI_RESPONSES_MODEL`` and then + ``AZURE_OPENAI_MODEL``. azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor reads ``AZURE_OPENAI_ENDPOINT``. credential: Azure credential or token provider for Entra auth. @@ -2613,8 +2603,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_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME`` for Azure routing. + routing, or ``AZURE_OPENAI_RESPONSES_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, @@ -2656,8 +2646,8 @@ class OpenAIChatClient( # type: ignore[misc] OpenAI routing reads ``OPENAI_API_KEY``, ``OPENAI_RESPONSES_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_DEPLOYMENT_NAME``, - ``AZURE_OPENAI_DEPLOYMENT_NAME``, and ``AZURE_OPENAI_API_VERSION``. + ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_RESPONSES_MODEL``, + ``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``. Examples: .. code-block:: python diff --git a/python/packages/openai/agent_framework_openai/_chat_completion_client.py b/python/packages/openai/agent_framework_openai/_chat_completion_client.py index 4828014e5b..0c70ea83a0 100644 --- a/python/packages/openai/agent_framework_openai/_chat_completion_client.py +++ b/python/packages/openai/agent_framework_openai/_chat_completion_client.py @@ -114,7 +114,7 @@ class OpenAIChatCompletionOptions(ChatOptions[ResponseModelT], Generic[ResponseM Extends ChatOptions with options specific to OpenAI's Chat Completions API. Keys: - model_id: The model to use for the request, + model: The model to use for the request, translates to ``model`` in OpenAI API. temperature: Sampling temperature between 0 and 2. top_p: Nucleus sampling parameter. @@ -155,7 +155,6 @@ OpenAIChatCompletionOptionsT = TypeVar( ) OPTION_TRANSLATIONS: dict[str, str] = { - "model_id": "model", # backward compat: accept model_id in options "allow_multiple_tool_calls": "parallel_tool_calls", "max_tokens": "max_completion_tokens", } @@ -246,8 +245,8 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc] Keyword Args: model: Model identifier to use for the request. When not provided, the constructor - reads ``AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME``. + 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``. credential: Azure credential or token provider for Entra auth. @@ -276,7 +275,6 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc] self, model: str | None = None, *, - model_id: str | None = None, api_key: str | SecretString | Callable[[], str | Awaitable[str]] | None = None, credential: AzureCredentialTypes | AzureTokenProvider | None = None, org_id: str | None = None, @@ -297,9 +295,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`` for OpenAI routing, - or ``AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME`` for Azure routing. - model_id: Deprecated alias for ``model``. + 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 auth. A callable token provider is also accepted for backwards compatibility, @@ -339,15 +335,9 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc] 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_CHAT_DEPLOYMENT_NAME``, - ``AZURE_OPENAI_DEPLOYMENT_NAME``, and ``AZURE_OPENAI_API_VERSION``. + ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_MODEL``, + ``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``. """ - if model_id is not None and model is None: - import warnings - - warnings.warn("model_id is deprecated, use model instead", DeprecationWarning, stacklevel=2) - model = model_id - settings, client, use_azure_client = load_openai_service_settings( model=model, api_key=api_key, @@ -362,11 +352,11 @@ class RawOpenAIChatCompletionClient( # type: ignore[misc] env_file_path=env_file_path, env_file_encoding=env_file_encoding, openai_model_fields=("chat_model", "model"), - azure_deployment_fields=("chat_deployment_name", "deployment_name"), + azure_model_fields=("chat_model", "model"), ) self.client = client - self.model: str = settings.get("model") or settings.get("deployment_name") or "" + self.model: str = settings.get("model") or "" # Store configuration for serialization self.org_id = settings.get("org_id") @@ -1098,8 +1088,8 @@ class OpenAIChatCompletionClient( # type: ignore[misc] Keyword Args: model: Model identifier to use for the request. When not provided, the constructor - reads ``AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME``. + 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``. credential: Azure credential or token provider for Entra auth. @@ -1146,8 +1136,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_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME`` for Azure 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 auth. A callable token provider is also accepted for backwards compatibility, @@ -1186,8 +1176,8 @@ class OpenAIChatCompletionClient( # type: ignore[misc] 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_CHAT_DEPLOYMENT_NAME``, - ``AZURE_OPENAI_DEPLOYMENT_NAME``, and ``AZURE_OPENAI_API_VERSION``. + ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_CHAT_MODEL``, + ``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``. Examples: .. code-block:: python diff --git a/python/packages/openai/agent_framework_openai/_embedding_client.py b/python/packages/openai/agent_framework_openai/_embedding_client.py index 6a637e29da..b11304dd27 100644 --- a/python/packages/openai/agent_framework_openai/_embedding_client.py +++ b/python/packages/openai/agent_framework_openai/_embedding_client.py @@ -123,8 +123,8 @@ class RawOpenAIEmbeddingClient( Keyword Args: model: Embedding deployment name. When not provided, the constructor reads - ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME``. + ``AZURE_OPENAI_EMBEDDING_MODEL`` and then + ``AZURE_OPENAI_MODEL``. azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor reads ``AZURE_OPENAI_ENDPOINT``. credential: Azure credential or token provider for Entra auth. @@ -150,7 +150,6 @@ class RawOpenAIEmbeddingClient( self, *, model: str | None = None, - model_id: str | None = None, api_key: str | SecretString | Callable[[], str | Awaitable[str]] | None = None, credential: AzureCredentialTypes | AzureTokenProvider | None = None, org_id: str | None = None, @@ -168,9 +167,8 @@ class RawOpenAIEmbeddingClient( Keyword Args: model: Embedding model or Azure OpenAI deployment name. When not provided, the constructor reads ``OPENAI_EMBEDDING_MODEL`` and then ``OPENAI_MODEL`` - for OpenAI. For Azure it first checks ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME`` - and then ``AZURE_OPENAI_DEPLOYMENT_NAME``. - model_id: Deprecated alias for ``model``. + for OpenAI. For Azure it first checks ``AZURE_OPENAI_EMBEDDING_MODEL`` + and then ``AZURE_OPENAI_MODEL``. 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, @@ -207,15 +205,9 @@ class RawOpenAIEmbeddingClient( OpenAI reads ``OPENAI_API_KEY``, ``OPENAI_EMBEDDING_MODEL``, ``OPENAI_MODEL``, ``OPENAI_ORG_ID``, and ``OPENAI_BASE_URL``. Azure reads ``AZURE_OPENAI_ENDPOINT``, ``AZURE_OPENAI_BASE_URL``, - ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME``, - ``AZURE_OPENAI_DEPLOYMENT_NAME``, and ``AZURE_OPENAI_API_VERSION``. + ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_EMBEDDING_MODEL``, + ``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``. """ - if model_id is not None and model is None: - import warnings - - warnings.warn("model_id is deprecated, use model instead", DeprecationWarning, stacklevel=2) - model = model_id - settings, client, use_azure_client = load_openai_service_settings( model=model, api_key=api_key, @@ -230,11 +222,11 @@ class RawOpenAIEmbeddingClient( env_file_path=env_file_path, env_file_encoding=env_file_encoding, openai_model_fields=("embedding_model", "model"), - azure_deployment_fields=("embedding_deployment_name", "deployment_name"), + azure_model_fields=("embedding_model", "model"), ) self.client = client - resolved_model = settings.get("model") or settings.get("deployment_name") + resolved_model = settings.get("model") self.model: str | None = resolved_model.strip() if isinstance(resolved_model, str) and resolved_model else None # Store configuration for serialization @@ -279,8 +271,7 @@ class RawOpenAIEmbeddingClient( return GeneratedEmbeddings([], options=options) # type: ignore opts: dict[str, Any] = options or {} # type: ignore - # backward compat: accept model_id in options - model = opts.get("model") or opts.get("model_id") or self.model + model = opts.get("model") or self.model if not model: raise ValueError("model is required") @@ -385,8 +376,8 @@ class OpenAIEmbeddingClient( Keyword Args: model: Embedding deployment name. When not provided, the constructor reads - ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME`` and then - ``AZURE_OPENAI_DEPLOYMENT_NAME``. + ``AZURE_OPENAI_EMBEDDING_MODEL`` and then + ``AZURE_OPENAI_MODEL``. azure_endpoint: Azure resource endpoint. When not provided explicitly, the constructor reads ``AZURE_OPENAI_ENDPOINT``. credential: Azure credential or token provider for Entra auth. @@ -429,8 +420,8 @@ class OpenAIEmbeddingClient( Keyword Args: model: Embedding model or Azure OpenAI deployment name. When not provided, the constructor reads ``OPENAI_EMBEDDING_MODEL`` and then ``OPENAI_MODEL`` - for OpenAI. For Azure it first checks ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME`` - and then ``AZURE_OPENAI_DEPLOYMENT_NAME``. + for OpenAI. For Azure it first checks ``AZURE_OPENAI_EMBEDDING_MODEL`` + and then ``AZURE_OPENAI_MODEL``. 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, @@ -467,8 +458,8 @@ class OpenAIEmbeddingClient( OpenAI reads ``OPENAI_API_KEY``, ``OPENAI_EMBEDDING_MODEL``, ``OPENAI_MODEL``, ``OPENAI_ORG_ID``, and ``OPENAI_BASE_URL``. Azure reads ``AZURE_OPENAI_ENDPOINT``, ``AZURE_OPENAI_BASE_URL``, - ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME``, - ``AZURE_OPENAI_DEPLOYMENT_NAME``, and ``AZURE_OPENAI_API_VERSION``. + ``AZURE_OPENAI_API_KEY``, ``AZURE_OPENAI_EMBEDDING_MODEL``, + ``AZURE_OPENAI_MODEL``, and ``AZURE_OPENAI_API_VERSION``. Examples: .. code-block:: python diff --git a/python/packages/openai/agent_framework_openai/_shared.py b/python/packages/openai/agent_framework_openai/_shared.py index 704583c30f..7afc4f2d25 100644 --- a/python/packages/openai/agent_framework_openai/_shared.py +++ b/python/packages/openai/agent_framework_openai/_shared.py @@ -104,17 +104,14 @@ class AzureOpenAISettings(TypedDict, total=False): endpoint: str | None base_url: str | None api_key: SecretString | None - deployment_name: str | None - embedding_deployment_name: str | None - chat_deployment_name: str | None - responses_deployment_name: str | None + model: str | None + embedding_model: str | None + chat_model: str | None + responses_model: str | None api_version: str | None OpenAIModelSettingName = Literal["model", "embedding_model", "chat_model", "responses_model"] -AzureDeploymentSettingName = Literal[ - "deployment_name", "embedding_deployment_name", "chat_deployment_name", "responses_deployment_name" -] OPENAI_MODEL_ENV_VARS: dict[OpenAIModelSettingName, str] = { "model": "OPENAI_MODEL", @@ -123,17 +120,17 @@ OPENAI_MODEL_ENV_VARS: dict[OpenAIModelSettingName, str] = { "responses_model": "OPENAI_RESPONSES_MODEL", } -AZURE_DEPLOYMENT_ENV_VARS: dict[AzureDeploymentSettingName, str] = { - "deployment_name": "AZURE_OPENAI_DEPLOYMENT_NAME", - "embedding_deployment_name": "AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME", - "chat_deployment_name": "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "responses_deployment_name": "AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME", +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", } def _resolve_named_setting( settings: Mapping[str, Any], - fields: Sequence[OpenAIModelSettingName | AzureDeploymentSettingName], + fields: Sequence[OpenAIModelSettingName], ) -> str | None: """Return the first populated value from ``fields``.""" for field in fields: @@ -163,10 +160,10 @@ def load_openai_service_settings( env_file_path: str | None, env_file_encoding: str | None, openai_model_fields: Sequence[OpenAIModelSettingName] = ("model",), - azure_deployment_fields: Sequence[AzureDeploymentSettingName] = ("deployment_name",), + azure_model_fields: Sequence[OpenAIModelSettingName] = ("model",), responses_mode: bool = False, ) -> tuple[dict[str, Any], AsyncOpenAI, bool]: - """Load OpenAI settings, including Azure OpenAI aliases. + """Load OpenAI settings, including Azure OpenAI model aliases. The generic OpenAI clients primarily read from ``OPENAI_*`` variables. Azure-specific environment variables are used only when an explicit Azure signal is present @@ -235,20 +232,18 @@ def load_openai_service_settings( env_file_encoding=env_file_encoding, ) if model is not None: - azure_settings[azure_deployment_fields[0]] = model + azure_settings[azure_model_fields[0]] = model client_args = {} - resolved_azure_deployment = _resolve_named_setting(azure_settings, azure_deployment_fields) - if resolved_azure_deployment is None and client: + resolved_azure_model = _resolve_named_setting(azure_settings, azure_model_fields) + if resolved_azure_model is None and client: azure_deployment = getattr(client, "_azure_deployment", None) if isinstance(azure_deployment, str) and azure_deployment: - resolved_azure_deployment = azure_deployment - if resolved_azure_deployment: - azure_settings["deployment_name"] = resolved_azure_deployment - client_args["azure_deployment"] = resolved_azure_deployment + resolved_azure_model = azure_deployment + if resolved_azure_model: + azure_settings["model"] = resolved_azure_model + client_args["azure_deployment"] = resolved_azure_model else: - deployment_env_guidance = _join_env_names([ - AZURE_DEPLOYMENT_ENV_VARS[field] for field in azure_deployment_fields - ]) + deployment_env_guidance = _join_env_names([AZURE_MODEL_ENV_VARS[field] for field in azure_model_fields]) has_azure_configuration = ( client is not None or azure_settings.get("endpoint") is not None @@ -261,7 +256,7 @@ def load_openai_service_settings( "'AZURE_OPENAI_BASE_URL'." ) raise SettingNotFoundError( - "Azure OpenAI client requires a deployment name, which can be provided via the 'model' parameter, " + "Azure OpenAI client requires a model, which can be provided via the 'model' parameter, " f"or the {deployment_env_guidance} environment variable." ) if client: diff --git a/python/packages/openai/tests/openai/conftest.py b/python/packages/openai/tests/openai/conftest.py index 34ea878a19..9e11067213 100644 --- a/python/packages/openai/tests/openai/conftest.py +++ b/python/packages/openai/tests/openai/conftest.py @@ -45,20 +45,15 @@ def openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # "OPENAI_EMBEDDING_MODEL", "OPENAI_CHAT_MODEL", "OPENAI_RESPONSES_MODEL", - "OPENAI_TEXT_MODEL_ID", - "OPENAI_TEXT_TO_IMAGE_MODEL_ID", - "OPENAI_AUDIO_TO_TEXT_MODEL_ID", - "OPENAI_TEXT_TO_AUDIO_MODEL_ID", - "OPENAI_REALTIME_MODEL_ID", "OPENAI_API_VERSION", "OPENAI_BASE_URL", "AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_BASE_URL", "AZURE_OPENAI_API_KEY", - "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME", - "AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME", - "AZURE_OPENAI_DEPLOYMENT_NAME", + "AZURE_OPENAI_CHAT_MODEL", + "AZURE_OPENAI_RESPONSES_MODEL", + "AZURE_OPENAI_EMBEDDING_MODEL", + "AZURE_OPENAI_MODEL", "AZURE_OPENAI_API_VERSION", ], ) @@ -66,13 +61,8 @@ def openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # env_vars = { "OPENAI_API_KEY": "test-dummy-key", "OPENAI_ORG_ID": "test_org_id", - "OPENAI_MODEL": "test_model_id", - "OPENAI_EMBEDDING_MODEL": "test_embedding_model_id", - "OPENAI_TEXT_MODEL_ID": "test_text_model_id", - "OPENAI_TEXT_TO_IMAGE_MODEL_ID": "test_text_to_image_model_id", - "OPENAI_AUDIO_TO_TEXT_MODEL_ID": "test_audio_to_text_model_id", - "OPENAI_TEXT_TO_AUDIO_MODEL_ID": "test_text_to_audio_model_id", - "OPENAI_REALTIME_MODEL_ID": "test_realtime_model_id", + "OPENAI_MODEL": "test_model", + "OPENAI_EMBEDDING_MODEL": "test_embedding_model", } env_vars.update(override_env_param_dict) # type: ignore @@ -104,30 +94,25 @@ def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dic "OPENAI_EMBEDDING_MODEL", "OPENAI_CHAT_MODEL", "OPENAI_RESPONSES_MODEL", - "OPENAI_TEXT_MODEL_ID", - "OPENAI_TEXT_TO_IMAGE_MODEL_ID", - "OPENAI_AUDIO_TO_TEXT_MODEL_ID", - "OPENAI_TEXT_TO_AUDIO_MODEL_ID", - "OPENAI_REALTIME_MODEL_ID", "OPENAI_API_VERSION", "OPENAI_BASE_URL", "AZURE_OPENAI_ENDPOINT", "AZURE_OPENAI_BASE_URL", "AZURE_OPENAI_API_KEY", - "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", - "AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME", - "AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME", - "AZURE_OPENAI_DEPLOYMENT_NAME", + "AZURE_OPENAI_CHAT_MODEL", + "AZURE_OPENAI_RESPONSES_MODEL", + "AZURE_OPENAI_EMBEDDING_MODEL", + "AZURE_OPENAI_MODEL", "AZURE_OPENAI_API_VERSION", ], ) env_vars = { "AZURE_OPENAI_ENDPOINT": "https://test-endpoint.openai.azure.com", - "AZURE_OPENAI_CHAT_DEPLOYMENT_NAME": "test_chat_deployment", - "AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME": "test_responses_deployment", - "AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME": "test_embedding_deployment", - "AZURE_OPENAI_DEPLOYMENT_NAME": "test_deployment", + "AZURE_OPENAI_CHAT_MODEL": "test_chat_deployment", + "AZURE_OPENAI_RESPONSES_MODEL": "test_responses_deployment", + "AZURE_OPENAI_EMBEDDING_MODEL": "test_embedding_deployment", + "AZURE_OPENAI_MODEL": "test_deployment", "AZURE_OPENAI_API_KEY": "test_api_key", "AZURE_OPENAI_API_VERSION": "2024-12-01-preview", } diff --git a/python/packages/openai/tests/openai/test_openai_chat_client.py b/python/packages/openai/tests/openai/test_openai_chat_client.py index 902e1d7c7a..dc7a119f2d 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_client.py +++ b/python/packages/openai/tests/openai/test_openai_chat_client.py @@ -151,11 +151,11 @@ def test_openai_chat_client_tool_methods_return_dict() -> None: def test_init_prefers_openai_responses_model(monkeypatch, openai_unit_test_env: dict[str, str]) -> None: - monkeypatch.setenv("OPENAI_RESPONSES_MODEL", "test_responses_model_id") + monkeypatch.setenv("OPENAI_RESPONSES_MODEL", "test_responses_model") openai_responses_client = OpenAIChatClient() - assert openai_responses_client.model == "test_responses_model_id" + assert openai_responses_client.model == "test_responses_model" def test_init_validation_fail() -> None: @@ -164,12 +164,12 @@ def test_init_validation_fail() -> None: OpenAIChatClient(api_key="34523", model={"test": "dict"}) # type: ignore -def test_init_model_id_constructor(openai_unit_test_env: dict[str, str]) -> None: +def test_init_model_constructor(openai_unit_test_env: dict[str, str]) -> None: # Test successful initialization - model_id = "test_model_id" - openai_responses_client = OpenAIChatClient(model=model_id) + model = "test_model" + openai_responses_client = OpenAIChatClient(model=model) - assert openai_responses_client.model == model_id + assert openai_responses_client.model == model assert isinstance(openai_responses_client, SupportsChatGetResponse) @@ -191,18 +191,18 @@ def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None: @pytest.mark.parametrize("exclude_list", [["OPENAI_MODEL"]], indirect=True) -def test_init_with_empty_model_id(openai_unit_test_env: dict[str, str]) -> None: +def test_init_with_empty_model(openai_unit_test_env: dict[str, str]) -> None: with pytest.raises(SettingNotFoundError): OpenAIChatClient() @pytest.mark.parametrize("exclude_list", [["OPENAI_API_KEY"]], indirect=True) def test_init_with_empty_api_key(openai_unit_test_env: dict[str, str]) -> None: - model_id = "test_model_id" + model = "test_model" with pytest.raises(SettingNotFoundError): OpenAIChatClient( - model=model_id, + model=model, ) diff --git a/python/packages/openai/tests/openai/test_openai_chat_client_azure.py b/python/packages/openai/tests/openai/test_openai_chat_client_azure.py index bda022e94a..756de8580d 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_client_azure.py +++ b/python/packages/openai/tests/openai/test_openai_chat_client_azure.py @@ -24,10 +24,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_DEPLOYMENT_NAME", "") == "" - and os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "") == "" - ), + or (os.getenv("AZURE_OPENAI_RESPONSES_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""), reason="No real Azure OpenAI endpoint or responses deployment provided; skipping integration tests.", ) @@ -39,9 +36,7 @@ def _with_azure_openai_debug() -> Any: try: return await func(*args, **kwargs) except Exception as exc: - model = os.getenv("AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME") or os.getenv( - "AZURE_OPENAI_DEPLOYMENT_NAME", "" - ) + model = os.getenv("AZURE_OPENAI_RESPONSES_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "") api_version = os.getenv("AZURE_OPENAI_API_VERSION") or "preview" endpoint = os.getenv("AZURE_OPENAI_ENDPOINT", "") debug_message = f"Azure OpenAI debug: endpoint={endpoint}, model={model}, api_version={api_version}" @@ -102,7 +97,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_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"] assert isinstance(client, SupportsChatGetResponse) assert isinstance(client.client, AsyncAzureOpenAI) assert client.OTEL_PROVIDER_NAME == "azure.ai.openai" @@ -112,7 +107,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_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"] @@ -147,7 +142,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_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"] @@ -155,34 +150,34 @@ 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_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_RESPONSES_MODEL", raising=False) client = OpenAIChatClient() - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) 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_DEPLOYMENT_NAME", raising=False) - monkeypatch.delenv("AZURE_OPENAI_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_RESPONSES_MODEL", raising=False) + monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False) monkeypatch.setenv("OPENAI_RESPONSES_MODEL", "test_responses_model") - with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a deployment name"): + with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"): OpenAIChatClient() 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_DEPLOYMENT_NAME", raising=False) - monkeypatch.delenv("AZURE_OPENAI_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_RESPONSES_MODEL", raising=False) + monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False) monkeypatch.delenv("OPENAI_RESPONSES_MODEL", raising=False) monkeypatch.setenv("OPENAI_MODEL", "gpt-5") - with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a deployment name"): + with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"): OpenAIChatClient() @@ -209,7 +204,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_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_RESPONSES_MODEL"] assert client.api_version is not None diff --git a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py index 8318d164bb..0b2bb75e2f 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_completion_client.py +++ b/python/packages/openai/tests/openai/test_openai_chat_completion_client.py @@ -79,11 +79,11 @@ 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_id") + monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_chat_model") open_ai_chat_completion = OpenAIChatCompletionClient() - assert open_ai_chat_completion.model == "test_chat_model_id" + assert open_ai_chat_completion.model == "test_chat_model" def test_init_validation_fail() -> None: @@ -92,12 +92,12 @@ def test_init_validation_fail() -> None: OpenAIChatCompletionClient(api_key="34523", model={"test": "dict"}) # type: ignore -def test_init_model_id_constructor(openai_unit_test_env: dict[str, str]) -> None: +def test_init_model_constructor(openai_unit_test_env: dict[str, str]) -> None: # Test successful initialization - model_id = "test_model_id" - open_ai_chat_completion = OpenAIChatCompletionClient(model=model_id) + model = "test_model" + open_ai_chat_completion = OpenAIChatCompletionClient(model=model) - assert open_ai_chat_completion.model == model_id + assert open_ai_chat_completion.model == model assert isinstance(open_ai_chat_completion, SupportsChatGetResponse) @@ -141,18 +141,18 @@ def test_init_base_url_from_settings_env() -> None: @pytest.mark.parametrize("exclude_list", [["OPENAI_MODEL"]], indirect=True) -def test_init_with_empty_model_id(openai_unit_test_env: dict[str, str]) -> None: +def test_init_with_empty_model(openai_unit_test_env: dict[str, str]) -> None: with pytest.raises(SettingNotFoundError): OpenAIChatCompletionClient() @pytest.mark.parametrize("exclude_list", [["OPENAI_API_KEY"]], indirect=True) def test_init_with_empty_api_key(openai_unit_test_env: dict[str, str]) -> None: - model_id = "test_model_id" + model = "test_model" with pytest.raises(SettingNotFoundError): OpenAIChatCompletionClient( - model=model_id, + model=model, ) @@ -1178,10 +1178,10 @@ def test_parse_text_with_refusal(openai_unit_test_env: dict[str, str]) -> None: assert message.contents[0].text == "I cannot provide that information." -def test_prepare_options_without_model_id(openai_unit_test_env: dict[str, str]) -> None: - """Test that prepare_options raises error when model_id is not set.""" +def test_prepare_options_without_model(openai_unit_test_env: dict[str, str]) -> None: + """Test that prepare_options raises error when model is not set.""" client = OpenAIChatCompletionClient() - client.model = None # Remove model_id + client.model = None # Remove model messages = [Message(role="user", text="test")] diff --git a/python/packages/openai/tests/openai/test_openai_chat_completion_client_azure.py b/python/packages/openai/tests/openai/test_openai_chat_completion_client_azure.py index f9edab227a..3a5e930d1f 100644 --- a/python/packages/openai/tests/openai/test_openai_chat_completion_client_azure.py +++ b/python/packages/openai/tests/openai/test_openai_chat_completion_client_azure.py @@ -29,9 +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_DEPLOYMENT_NAME", "") == "" and os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "") == "" - ), + or (os.getenv("AZURE_OPENAI_CHAT_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""), reason="No real Azure OpenAI endpoint or chat deployment provided; skipping integration tests.", ) @@ -43,9 +41,7 @@ def _with_azure_openai_debug() -> Any: try: return await func(*args, **kwargs) except Exception as exc: - model = os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME") or os.getenv( - "AZURE_OPENAI_DEPLOYMENT_NAME", "" - ) + model = os.getenv("AZURE_OPENAI_CHAT_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "") api_version = os.getenv("AZURE_OPENAI_API_VERSION", "") endpoint = os.getenv("AZURE_OPENAI_ENDPOINT", "") debug_message = f"Azure OpenAI debug: endpoint={endpoint}, model={model}, api_version={api_version}" @@ -82,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_DEPLOYMENT_NAME"] + 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" @@ -93,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_DEPLOYMENT_NAME"] + 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"] @@ -115,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_DEPLOYMENT_NAME"] + 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"] @@ -123,34 +119,34 @@ 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_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False) client = OpenAIChatCompletionClient() - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) 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_DEPLOYMENT_NAME", raising=False) - monkeypatch.delenv("AZURE_OPENAI_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False) + monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False) monkeypatch.setenv("OPENAI_CHAT_MODEL", "test_chat_model") - with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a deployment name"): + with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"): OpenAIChatCompletionClient() 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_DEPLOYMENT_NAME", raising=False) - monkeypatch.delenv("AZURE_OPENAI_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_CHAT_MODEL", raising=False) + monkeypatch.delenv("AZURE_OPENAI_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 deployment name"): + with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"): OpenAIChatCompletionClient() diff --git a/python/packages/openai/tests/openai/test_openai_embedding_client.py b/python/packages/openai/tests/openai/test_openai_embedding_client.py index 3244f9620b..1690c2b70e 100644 --- a/python/packages/openai/tests/openai/test_openai_embedding_client.py +++ b/python/packages/openai/tests/openai/test_openai_embedding_client.py @@ -185,7 +185,7 @@ async def test_openai_base64_decoding(openai_unit_test_env: dict[str, str]) -> N assert abs(expected - actual) < 1e-6 -async def test_openai_error_when_no_model_id() -> None: +async def test_openai_error_when_no_model() -> None: client = OpenAIEmbeddingClient.__new__(OpenAIEmbeddingClient) client.model = None client.client = MagicMock() diff --git a/python/packages/openai/tests/openai/test_openai_embedding_client_azure.py b/python/packages/openai/tests/openai/test_openai_embedding_client_azure.py index 3cf62a064d..2d3c457bf6 100644 --- a/python/packages/openai/tests/openai/test_openai_embedding_client_azure.py +++ b/python/packages/openai/tests/openai/test_openai_embedding_client_azure.py @@ -19,10 +19,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_EMBEDDING_DEPLOYMENT_NAME", "") == "" - and os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "") == "" - ), + or (os.getenv("AZURE_OPENAI_EMBEDDING_MODEL", "") == "" and os.getenv("AZURE_OPENAI_MODEL", "") == ""), reason="No real Azure OpenAI endpoint or embedding deployment provided; skipping integration tests.", ) @@ -34,9 +31,7 @@ def _with_azure_openai_debug() -> Any: try: return await func(*args, **kwargs) except Exception as exc: - model = os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME") or os.getenv( - "AZURE_OPENAI_DEPLOYMENT_NAME", "" - ) + model = os.getenv("AZURE_OPENAI_EMBEDDING_MODEL") or os.getenv("AZURE_OPENAI_MODEL", "") api_version = os.getenv("AZURE_OPENAI_API_VERSION", "") endpoint = os.getenv("AZURE_OPENAI_ENDPOINT", "") debug_message = f"Azure OpenAI debug: endpoint={endpoint}, model={model}, api_version={api_version}" @@ -54,7 +49,7 @@ def _with_azure_openai_debug() -> Any: def _get_azure_embedding_deployment_name() -> str: - return os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME") or os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"] + return os.getenv("AZURE_OPENAI_EMBEDDING_MODEL") or os.environ["AZURE_OPENAI_MODEL"] def _create_azure_embedding_client( @@ -77,7 +72,7 @@ def _create_azure_embedding_client( def test_init_with_azure_endpoint(azure_openai_unit_test_env: dict[str, str]) -> None: client = _create_azure_embedding_client() - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) assert client.OTEL_PROVIDER_NAME == "azure.ai.openai" assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"] @@ -87,7 +82,7 @@ def test_init_with_azure_endpoint(azure_openai_unit_test_env: dict[str, str]) -> def test_init_auto_detects_azure_embedding_env(azure_openai_unit_test_env: dict[str, str]) -> None: client = OpenAIEmbeddingClient() - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"] @@ -95,34 +90,34 @@ def test_init_auto_detects_azure_embedding_env(azure_openai_unit_test_env: dict[ def test_init_falls_back_to_generic_azure_deployment_env( monkeypatch, azure_openai_unit_test_env: dict[str, str] ) -> None: - monkeypatch.delenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_EMBEDDING_MODEL", raising=False) client = OpenAIEmbeddingClient() - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) def test_init_does_not_fall_back_to_openai_embedding_model_for_azure_env( monkeypatch, azure_openai_unit_test_env: dict[str, str] ) -> None: - monkeypatch.delenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME", raising=False) - monkeypatch.delenv("AZURE_OPENAI_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_EMBEDDING_MODEL", raising=False) + monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False) monkeypatch.setenv("OPENAI_EMBEDDING_MODEL", "text-embedding-3-small") - with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a deployment name"): + with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"): OpenAIEmbeddingClient() 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_EMBEDDING_DEPLOYMENT_NAME", raising=False) - monkeypatch.delenv("AZURE_OPENAI_DEPLOYMENT_NAME", raising=False) + monkeypatch.delenv("AZURE_OPENAI_EMBEDDING_MODEL", raising=False) + monkeypatch.delenv("AZURE_OPENAI_MODEL", raising=False) monkeypatch.delenv("OPENAI_EMBEDDING_MODEL", raising=False) monkeypatch.setenv("OPENAI_MODEL", "gpt-5") - with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a deployment name"): + with pytest.raises(SettingNotFoundError, match="Azure OpenAI client requires a model"): OpenAIEmbeddingClient() @@ -156,7 +151,7 @@ def test_explicit_credential_wins_over_openai_api_key(monkeypatch, azure_openai_ client = OpenAIEmbeddingClient(credential=lambda: "token") - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_MODEL"] assert isinstance(client.client, AsyncAzureOpenAI) assert client.azure_endpoint == azure_openai_unit_test_env["AZURE_OPENAI_ENDPOINT"] @@ -177,7 +172,7 @@ def test_init_with_credential_wraps_async_token_credential( client = OpenAIEmbeddingClient(credential=credential) assert isinstance(client.client, AsyncAzureOpenAI) - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_MODEL"] mock_provider.assert_called_once_with(credential, "https://cognitiveservices.azure.com/.default") @@ -185,7 +180,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 = _create_azure_embedding_client() - assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"] + assert client.model == azure_openai_unit_test_env["AZURE_OPENAI_EMBEDDING_MODEL"] assert client.api_version == "2024-10-21" diff --git a/python/packages/purview/README.md b/python/packages/purview/README.md index cbe2999040..a802cd9615 100644 --- a/python/packages/purview/README.md +++ b/python/packages/purview/README.md @@ -245,7 +245,7 @@ from azure.identity import DefaultAzureCredential credential = DefaultAzureCredential() client = OpenAIChatCompletionClient( - model=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + model=os.environ["AZURE_OPENAI_MODEL"], azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], credential=credential, middleware=[ diff --git a/python/samples/02-agents/chat_client/README.md b/python/samples/02-agents/chat_client/README.md index 80b1e0ea1a..0a67230d51 100644 --- a/python/samples/02-agents/chat_client/README.md +++ b/python/samples/02-agents/chat_client/README.md @@ -51,7 +51,7 @@ Depending on the selected client, set the appropriate environment variables: **For Azure OpenAI clients (`azure_openai_responses` and `azure_openai_chat_completion`):** - `AZURE_OPENAI_ENDPOINT`: Your Azure OpenAI endpoint -- `AZURE_OPENAI_DEPLOYMENT_NAME`: The Azure OpenAI deployment used by the sample +- `AZURE_OPENAI_MODEL`: The Azure OpenAI deployment used by the sample - `AZURE_OPENAI_API_VERSION` (optional): Azure OpenAI API version override - `AZURE_OPENAI_API_KEY` (optional): Azure OpenAI API key if you are not using `AzureCliCredential` @@ -66,13 +66,13 @@ Depending on the selected client, set the appropriate environment variables: **For Anthropic client (`anthropic`):** - `ANTHROPIC_API_KEY`: Your Anthropic API key -- `ANTHROPIC_CHAT_MODEL_ID`: The Anthropic model ID (for example, `claude-sonnet-4-5`) +- `ANTHROPIC_CHAT_MODEL`: The Anthropic model to use (for example, `claude-sonnet-4-5`) **For Ollama client (`ollama`):** - `OLLAMA_HOST`: Ollama server URL (defaults to `http://localhost:11434` if unset) -- `OLLAMA_MODEL_ID`: Ollama model name (for example, `mistral`, `qwen2.5:8b`) +- `OLLAMA_MODEL`: Ollama model name (for example, `mistral`, `qwen2.5:8b`) **For Bedrock client (`bedrock`):** -- `BEDROCK_CHAT_MODEL_ID`: Bedrock model ID (for example, `anthropic.claude-3-5-sonnet-20240620-v1:0`) +- `BEDROCK_CHAT_MODEL`: Bedrock model ID (for example, `anthropic.claude-3-5-sonnet-20240620-v1:0`) - `BEDROCK_REGION`: AWS region (defaults to `us-east-1` if unset) - AWS credentials via standard environment variables (for example, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`) diff --git a/python/samples/02-agents/chat_client/chat_response_cancellation.py b/python/samples/02-agents/chat_client/chat_response_cancellation.py index 6c7bc39894..1455026d64 100644 --- a/python/samples/02-agents/chat_client/chat_response_cancellation.py +++ b/python/samples/02-agents/chat_client/chat_response_cancellation.py @@ -24,7 +24,7 @@ async def main() -> None: Creates a task for the chat request, waits briefly, then cancels it to show proper cleanup. Configuration: - - OpenAI model ID: Use "model_id" parameter or "OPENAI_MODEL" environment variable + - OpenAI model ID: Use "model" parameter or "OPENAI_MODEL" environment variable - OpenAI API key: Use "api_key" parameter or "OPENAI_API_KEY" environment variable """ client = FoundryChatClient(credential=AzureCliCredential()) diff --git a/python/samples/02-agents/chat_client/custom_chat_client.py b/python/samples/02-agents/chat_client/custom_chat_client.py index c677c09d8b..7a7406f23e 100644 --- a/python/samples/02-agents/chat_client/custom_chat_client.py +++ b/python/samples/02-agents/chat_client/custom_chat_client.py @@ -102,7 +102,7 @@ class EchoingChatClient(BaseChatClient[OptionsT]): response = ChatResponse( messages=[response_message], - model_id="echo-model-v1", + model="echo-model-v1", response_id=f"echo-resp-{random.randint(1000, 9999)}", ) @@ -120,7 +120,7 @@ class EchoingChatClient(BaseChatClient[OptionsT]): contents=[Content.from_text(char)], role="assistant", response_id=f"echo-stream-resp-{random.randint(1000, 9999)}", - model_id="echo-model-v1", + model="echo-model-v1", ) await asyncio.sleep(stream_delay_seconds) diff --git a/python/samples/02-agents/compaction/tiktoken_tokenizer.py b/python/samples/02-agents/compaction/tiktoken_tokenizer.py index c0ba93c806..ef109eaaa3 100644 --- a/python/samples/02-agents/compaction/tiktoken_tokenizer.py +++ b/python/samples/02-agents/compaction/tiktoken_tokenizer.py @@ -33,9 +33,9 @@ Key components: class TiktokenTokenizer(TokenizerProtocol): """TokenizerProtocol implementation backed by tiktoken's o200k_base (gpt-4.1 and up default) encoding.""" - def __init__(self, *, encoding_name: str = "o200k_base", model_name: str | None = None) -> None: - if model_name is not None: - self._encoding = tiktoken.encoding_for_model(model_name) + def __init__(self, *, encoding_name: str = "o200k_base", model: str | None = None) -> None: + if model is not None: + self._encoding = tiktoken.encoding_for_model(model) else: self._encoding: Any = tiktoken.get_encoding(encoding_name) diff --git a/python/samples/02-agents/context_providers/azure_ai_foundry_memory.py b/python/samples/02-agents/context_providers/azure_ai_foundry_memory.py index 9c27e5857f..fbbeb20b14 100644 --- a/python/samples/02-agents/context_providers/azure_ai_foundry_memory.py +++ b/python/samples/02-agents/context_providers/azure_ai_foundry_memory.py @@ -33,7 +33,7 @@ rather than chat history. The memory store is deleted at the end of the run. Prerequisites: 1. Set FOUNDRY_PROJECT_ENDPOINT environment variable 2. Set FOUNDRY_MODEL for the chat/responses model -3. Set AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME for the embedding model +3. Set AZURE_OPENAI_EMBEDDING_MODEL for the embedding model 4. Deploy both a chat model (e.g. gpt-4) and an embedding model (e.g. text-embedding-3-small) """ load_dotenv() @@ -55,7 +55,7 @@ async def main() -> None: ) memory_store_definition = MemoryStoreDefaultDefinition( chat_model=os.environ["FOUNDRY_MODEL"], - embedding_model=os.environ["AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"], + embedding_model=os.environ["AZURE_OPENAI_EMBEDDING_MODEL"], options=options, ) print(f"Creating memory store '{memory_store_name}'...") diff --git a/python/samples/02-agents/context_providers/azure_ai_search/search_context_semantic.py b/python/samples/02-agents/context_providers/azure_ai_search/search_context_semantic.py index d12b7df849..5f2a57f511 100644 --- a/python/samples/02-agents/context_providers/azure_ai_search/search_context_semantic.py +++ b/python/samples/02-agents/context_providers/azure_ai_search/search_context_semantic.py @@ -32,7 +32,7 @@ Prerequisites: - AZURE_SEARCH_INDEX_NAME: Your search index name - FOUNDRY_PROJECT_ENDPOINT: Your Azure AI Foundry project endpoint - FOUNDRY_MODEL: Your model deployment name (e.g., "gpt-4o") - - AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME: (Optional) Your Azure OpenAI embedding deployment for hybrid search + - AZURE_OPENAI_EMBEDDING_MODEL: (Optional) Your Azure OpenAI embedding deployment for hybrid search - AZURE_OPENAI_ENDPOINT: (Optional) Your Azure OpenAI resource URL, required if using Azure OpenAI embeddings """ @@ -56,7 +56,7 @@ async def main() -> None: project_endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] model_deployment = os.environ.get("FOUNDRY_MODEL", "gpt-4o") openai_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") - embedding_deployment = os.environ.get("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME") + embedding_deployment = os.environ.get("AZURE_OPENAI_EMBEDDING_MODEL") embedding_client = None if openai_endpoint and embedding_deployment: diff --git a/python/samples/02-agents/declarative/README.md b/python/samples/02-agents/declarative/README.md index 045280218e..4bc4489dc2 100644 --- a/python/samples/02-agents/declarative/README.md +++ b/python/samples/02-agents/declarative/README.md @@ -159,7 +159,7 @@ agent_factory = AgentFactory( "MyProvider": { "package": "my_custom_module", "name": "MyCustomChatClient", - "model_id_field": "model_id", + "model_field": "model", } } ) @@ -176,7 +176,7 @@ agent = agent_factory.create_agent_from_yaml_path(Path("custom_provider.yaml")) This allows you to extend the declarative framework with custom chat client implementations. The mapping requires: - **package**: The Python package/module to import from - **name**: The class name of your SupportsChatGetResponse implementation -- **model_id_field**: The constructor parameter name that accepts the value of the `model.id` field from the YAML +- **model_field**: The constructor parameter name that accepts the value of the `model.id` field from the YAML You can reference your custom provider using either `Provider.ApiType` format or just `Provider` in your YAML configuration, as long as it matches the registered mapping. diff --git a/python/samples/02-agents/devui/.env.example b/python/samples/02-agents/devui/.env.example index 394dc7465d..712a1f7a30 100644 --- a/python/samples/02-agents/devui/.env.example +++ b/python/samples/02-agents/devui/.env.example @@ -8,8 +8,8 @@ FOUNDRY_MODEL=gpt-4o # Azure OpenAI workflow sample AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com -AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME=gpt-4o +AZURE_OPENAI_RESPONSES_MODEL=gpt-4o # Optional fallback env name also supported by workflow_with_agents/workflow.py: -AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o +AZURE_OPENAI_MODEL=gpt-4o # Optional if you need to override the default API version: AZURE_OPENAI_API_VERSION=2024-10-21 diff --git a/python/samples/02-agents/devui/README.md b/python/samples/02-agents/devui/README.md index 8a0ed60b6f..8498a0cab5 100644 --- a/python/samples/02-agents/devui/README.md +++ b/python/samples/02-agents/devui/README.md @@ -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_DEPLOYMENT_NAME` or `AZURE_OPENAI_DEPLOYMENT_NAME`; 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_RESPONSES_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,8 +130,8 @@ 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_DEPLOYMENT_NAME="gpt-4o" -export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o" +export AZURE_OPENAI_RESPONSES_MODEL="gpt-4o" +export AZURE_OPENAI_MODEL="gpt-4o" az login ``` diff --git a/python/samples/02-agents/devui/workflow_with_agents/.env.example b/python/samples/02-agents/devui/workflow_with_agents/.env.example index 520cd181cc..ebbf5ccc9e 100644 --- a/python/samples/02-agents/devui/workflow_with_agents/.env.example +++ b/python/samples/02-agents/devui/workflow_with_agents/.env.example @@ -2,8 +2,8 @@ # 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_DEPLOYMENT_NAME=gpt-4o +AZURE_OPENAI_RESPONSES_MODEL=gpt-4o # Optional fallback env name also supported by the client: -# AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o +# AZURE_OPENAI_MODEL=gpt-4o # Optional if you need to override the default API version: AZURE_OPENAI_API_VERSION=2024-10-21 diff --git a/python/samples/02-agents/devui/workflow_with_agents/workflow.py b/python/samples/02-agents/devui/workflow_with_agents/workflow.py index cda57a67f7..598e7201f7 100644 --- a/python/samples/02-agents/devui/workflow_with_agents/workflow.py +++ b/python/samples/02-agents/devui/workflow_with_agents/workflow.py @@ -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_DEPLOYMENT_NAME") or os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME"), + model=os.environ.get("AZURE_OPENAI_RESPONSES_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(), diff --git a/python/samples/02-agents/embeddings/azure_ai_inference_embeddings.py b/python/samples/02-agents/embeddings/azure_ai_inference_embeddings.py index e806166f16..931d8a8759 100644 --- a/python/samples/02-agents/embeddings/azure_ai_inference_embeddings.py +++ b/python/samples/02-agents/embeddings/azure_ai_inference_embeddings.py @@ -31,9 +31,9 @@ Prerequisites: - AZURE_AI_INFERENCE_ENDPOINT: Your Azure AI model inference endpoint URL, for instance: https://.azure-api.net//models - AZURE_AI_INFERENCE_API_KEY: Your API key - - AZURE_AI_INFERENCE_EMBEDDING_MODEL_ID: The text embedding model name + - AZURE_AI_INFERENCE_EMBEDDING_MODEL: The text embedding model name (e.g. "text-embedding-3-small") - - AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID: The image embedding model name + - AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL: The image embedding model name (e.g. "Cohere-embed-v3-english") """ @@ -49,7 +49,7 @@ async def main() -> None: result = await client.get_embeddings([image_content]) print(f"Image embedding dimensions: {result[0].dimensions}") print(f"First 5 values: {result[0].vector[:5]}") - print(f"Model: {result[0].model_id}") + print(f"Model: {result[0].model}") print(f"Usage: {result.usage}") print() diff --git a/python/samples/02-agents/embeddings/azure_openai_embeddings.py b/python/samples/02-agents/embeddings/azure_openai_embeddings.py index 460bbcf7de..30f3cf4569 100644 --- a/python/samples/02-agents/embeddings/azure_openai_embeddings.py +++ b/python/samples/02-agents/embeddings/azure_openai_embeddings.py @@ -14,7 +14,7 @@ from dotenv import load_dotenv Prerequisites: Set the following environment variables or add them to a local ``.env`` file: - ``AZURE_OPENAI_ENDPOINT``: Your Azure OpenAI endpoint URL - - ``AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME``: The embedding deployment name + - ``AZURE_OPENAI_EMBEDDING_MODEL``: The embedding deployment name - ``AZURE_OPENAI_API_VERSION``: Optional API version override Sign in with ``az login`` before running the sample. @@ -27,7 +27,7 @@ async def main() -> None: """Generate embeddings with Azure OpenAI.""" async with AzureCliCredential() as credential: client = OpenAIEmbeddingClient( - model=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME"), + model=os.getenv("AZURE_OPENAI_EMBEDDING_MODEL"), azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), credential=credential, diff --git a/python/samples/02-agents/evaluation/evaluate_with_expected.py b/python/samples/02-agents/evaluation/evaluate_with_expected.py index de44c4e7e9..a165593c18 100644 --- a/python/samples/02-agents/evaluation/evaluate_with_expected.py +++ b/python/samples/02-agents/evaluation/evaluate_with_expected.py @@ -41,7 +41,7 @@ def response_matches_expected(response: str, expected_output: str) -> float: async def main() -> None: client = FoundryChatClient( project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME", "gpt-4o"), + model=os.environ.get("FOUNDRY_MODEL", "gpt-4o"), credential=AzureCliCredential(), ) diff --git a/python/samples/02-agents/multimodal_input/README.md b/python/samples/02-agents/multimodal_input/README.md index 6feda8e62c..da99e71057 100644 --- a/python/samples/02-agents/multimodal_input/README.md +++ b/python/samples/02-agents/multimodal_input/README.md @@ -32,8 +32,8 @@ Set the following environment variables before running the examples: **For Azure OpenAI:** - `AZURE_OPENAI_ENDPOINT`: Your Azure OpenAI endpoint -- `AZURE_OPENAI_DEPLOYMENT_NAME`: The name of your Azure OpenAI chat model deployment -- `AZURE_OPENAI_DEPLOYMENT_NAME`: The name of your Azure OpenAI responses model deployment +- `AZURE_OPENAI_MODEL`: The name of your Azure OpenAI chat model deployment +- `AZURE_OPENAI_MODEL`: The name of your Azure OpenAI responses model deployment Optionally for Azure OpenAI: - `AZURE_OPENAI_API_VERSION`: The API version to use (default is `2024-10-21`) diff --git a/python/samples/02-agents/multimodal_input/azure_chat_multimodal.py b/python/samples/02-agents/multimodal_input/azure_chat_multimodal.py index 8a141fa9ce..2d7c5c9a20 100644 --- a/python/samples/02-agents/multimodal_input/azure_chat_multimodal.py +++ b/python/samples/02-agents/multimodal_input/azure_chat_multimodal.py @@ -23,7 +23,7 @@ async def test_image() -> None: # For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred # authentication option. Requires AZURE_OPENAI_ENDPOINT and FOUNDRY_MODEL # environment variables to be set. - # Alternatively, you can pass deployment_name explicitly: + # Alternatively, you can pass model explicitly: # client = FoundryChatClient(credential=AzureCliCredential(), model="your-deployment-name") client = FoundryChatClient(credential=AzureCliCredential()) image_uri = create_sample_image() diff --git a/python/samples/02-agents/multimodal_input/azure_responses_multimodal.py b/python/samples/02-agents/multimodal_input/azure_responses_multimodal.py index 61f14749e7..ec0a684c47 100644 --- a/python/samples/02-agents/multimodal_input/azure_responses_multimodal.py +++ b/python/samples/02-agents/multimodal_input/azure_responses_multimodal.py @@ -32,7 +32,7 @@ async def test_image() -> None: # For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred # authentication option. Requires AZURE_OPENAI_ENDPOINT and FOUNDRY_MODEL # environment variables to be set. - # Alternatively, you can pass deployment_name explicitly: + # Alternatively, you can pass model explicitly: # client = FoundryChatClient(credential=AzureCliCredential(), model="your-deployment-name") client = FoundryChatClient(credential=AzureCliCredential()) diff --git a/python/samples/02-agents/providers/amazon/README.md b/python/samples/02-agents/providers/amazon/README.md index ab10aeecfd..5dfd3e2c82 100644 --- a/python/samples/02-agents/providers/amazon/README.md +++ b/python/samples/02-agents/providers/amazon/README.md @@ -1,7 +1,7 @@ # Bedrock Examples This folder contains examples demonstrating how to use AWS Bedrock models with the Agent Framework. The sample -uses `BEDROCK_CHAT_MODEL_ID`, `BEDROCK_REGION`, and AWS credentials (`AWS_ACCESS_KEY_ID`, +uses `BEDROCK_CHAT_MODEL`, `BEDROCK_REGION`, and AWS credentials (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`). ## Examples @@ -12,6 +12,6 @@ uses `BEDROCK_CHAT_MODEL_ID`, `BEDROCK_REGION`, and AWS credentials (`AWS_ACCESS ## Environment Variables -- `BEDROCK_CHAT_MODEL_ID`: Bedrock model ID (for example, `anthropic.claude-3-5-sonnet-20240620-v1:0`) +- `BEDROCK_CHAT_MODEL`: Bedrock model ID (for example, `anthropic.claude-3-5-sonnet-20240620-v1:0`) - `BEDROCK_REGION`: AWS region (defaults to `us-east-1` if unset) - AWS credentials via standard variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`) diff --git a/python/samples/02-agents/providers/amazon/bedrock_chat_client.py b/python/samples/02-agents/providers/amazon/bedrock_chat_client.py index a61944bcbd..2c1f0b8845 100644 --- a/python/samples/02-agents/providers/amazon/bedrock_chat_client.py +++ b/python/samples/02-agents/providers/amazon/bedrock_chat_client.py @@ -17,7 +17,7 @@ Bedrock Chat Client Example This sample demonstrates using `BedrockChatClient` with an agent and a simple tool. Environment variables used: -- `BEDROCK_CHAT_MODEL_ID` +- `BEDROCK_CHAT_MODEL` - `BEDROCK_REGION` (defaults to `us-east-1` if unset) - AWS credentials via standard variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`) diff --git a/python/samples/02-agents/providers/anthropic/README.md b/python/samples/02-agents/providers/anthropic/README.md index 5151ade855..0db183490a 100644 --- a/python/samples/02-agents/providers/anthropic/README.md +++ b/python/samples/02-agents/providers/anthropic/README.md @@ -28,14 +28,14 @@ This folder contains examples demonstrating how to use Anthropic's Claude models ### Anthropic Client - `ANTHROPIC_API_KEY`: Your Anthropic API key (get one from [Anthropic Console](https://console.anthropic.com/)) -- `ANTHROPIC_CHAT_MODEL_ID`: The Claude model to use (e.g., `claude-haiku-4-5`, `claude-sonnet-4-5-20250929`) +- `ANTHROPIC_CHAT_MODEL`: The Claude model to use (e.g., `claude-haiku-4-5`, `claude-sonnet-4-5-20250929`) ### Foundry - `ANTHROPIC_FOUNDRY_API_KEY`: Your Foundry Anthropic API key - `ANTHROPIC_FOUNDRY_RESOURCE`: Your Foundry resource name (for example `my-foundry-resource`) - `ANTHROPIC_FOUNDRY_BASE_URL`: Optional full Foundry Anthropic base URL alternative to `ANTHROPIC_FOUNDRY_RESOURCE` -- `ANTHROPIC_CHAT_MODEL_ID`: The Claude model to use in Foundry (e.g., `claude-haiku-4-5`) +- `ANTHROPIC_CHAT_MODEL`: The Claude model to use in Foundry (e.g., `claude-haiku-4-5`) ### Claude Agent diff --git a/python/samples/02-agents/providers/anthropic/anthropic_basic.py b/python/samples/02-agents/providers/anthropic/anthropic_basic.py index 85f0485d66..3ff9f81504 100644 --- a/python/samples/02-agents/providers/anthropic/anthropic_basic.py +++ b/python/samples/02-agents/providers/anthropic/anthropic_basic.py @@ -35,7 +35,7 @@ async def non_streaming_example() -> None: print("=== Non-streaming Response Example ===") agent = Agent( - client=AnthropicClient(model_id="claude-sonnet-4-5-20250929"), + client=AnthropicClient(model="claude-sonnet-4-5-20250929"), name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather, @@ -52,7 +52,7 @@ async def streaming_example() -> None: print("=== Streaming Response Example ===") agent = Agent( - client=AnthropicClient(model_id="claude-sonnet-4-5-20250929"), + client=AnthropicClient(model="claude-sonnet-4-5-20250929"), name="WeatherAgent", instructions="You are a helpful weather agent.", tools=get_weather, diff --git a/python/samples/02-agents/providers/anthropic/anthropic_foundry.py b/python/samples/02-agents/providers/anthropic/anthropic_foundry.py index dd66262131..8807059362 100644 --- a/python/samples/02-agents/providers/anthropic/anthropic_foundry.py +++ b/python/samples/02-agents/providers/anthropic/anthropic_foundry.py @@ -2,8 +2,7 @@ import asyncio from agent_framework import Agent -from agent_framework.anthropic import AnthropicClient -from anthropic import AsyncAnthropicFoundry +from agent_framework.foundry import AnthropicFoundryClient from dotenv import load_dotenv # Load environment variables from .env file @@ -27,14 +26,14 @@ To use the Foundry integration ensure you have the following environment variabl - ANTHROPIC_FOUNDRY_BASE_URL Optional alternative to ANTHROPIC_FOUNDRY_RESOURCE. Should be something like https://.services.ai.azure.com/anthropic/ -- ANTHROPIC_CHAT_MODEL_ID +- ANTHROPIC_CHAT_MODEL Should be something like claude-haiku-4-5 """ async def main() -> None: """Example of streaming response (get results as they are generated).""" - client = AnthropicClient(anthropic_client=AsyncAnthropicFoundry()) + client = AnthropicFoundryClient() # Create MCP tool configuration using instance method mcp_tool = client.get_mcp_tool( diff --git a/python/samples/02-agents/providers/anthropic/anthropic_skills.py b/python/samples/02-agents/providers/anthropic/anthropic_skills.py index a93874c269..9d8b2df92b 100644 --- a/python/samples/02-agents/providers/anthropic/anthropic_skills.py +++ b/python/samples/02-agents/providers/anthropic/anthropic_skills.py @@ -29,7 +29,7 @@ async def main() -> None: client = AnthropicClient[AnthropicChatOptions](additional_beta_flags=["skills-2025-10-02"]) # List Anthropic-managed Skills - skills = await client.anthropic_client.beta.skills.list(source="anthropic", betas=["skills-2025-10-02"]) + skills = await client.anthropic_client.beta.skills.list(source="anthropic", betas=["skills-2025-10-02"]) # type: ignore for skill in skills.data: print(f"{skill.source}: {skill.id} (version: {skill.latest_version})") @@ -81,7 +81,7 @@ async def main() -> None: # Since I'm using the pptx skill, the files will be PowerPoint presentations print("Generated files:") for idx, file in enumerate(files): - file_content = await client.anthropic_client.beta.files.download( + file_content = await client.anthropic_client.beta.files.download( # type: ignore file_id=file.file_id, betas=["files-api-2025-04-14"] ) with open(Path(__file__).parent / f"python_programming-{idx}.pptx", "wb") as f: diff --git a/python/samples/02-agents/providers/azure/README.md b/python/samples/02-agents/providers/azure/README.md index cd34fe2717..ab33281a37 100644 --- a/python/samples/02-agents/providers/azure/README.md +++ b/python/samples/02-agents/providers/azure/README.md @@ -26,7 +26,7 @@ This folder contains Azure-backed samples for the generic OpenAI clients in Set these before running the Azure provider samples: - `AZURE_OPENAI_ENDPOINT` -- `AZURE_OPENAI_DEPLOYMENT_NAME` +- `AZURE_OPENAI_MODEL` Optionally, you can also set: diff --git a/python/samples/02-agents/providers/azure/openai_chat_completion_client_basic.py b/python/samples/02-agents/providers/azure/openai_chat_completion_client_basic.py index 030828da89..9381d7f80c 100644 --- a/python/samples/02-agents/providers/azure/openai_chat_completion_client_basic.py +++ b/python/samples/02-agents/providers/azure/openai_chat_completion_client_basic.py @@ -38,7 +38,7 @@ async def non_streaming_example() -> None: agent = Agent( client=OpenAIChatCompletionClient( - model=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), + model=os.getenv("AZURE_OPENAI_MODEL"), azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), credential=AzureCliCredential(), @@ -60,7 +60,7 @@ async def streaming_example() -> None: agent = Agent( client=OpenAIChatCompletionClient( - model=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), + model=os.getenv("AZURE_OPENAI_MODEL"), azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), credential=AzureCliCredential(), diff --git a/python/samples/02-agents/providers/azure/openai_chat_completion_client_with_explicit_settings.py b/python/samples/02-agents/providers/azure/openai_chat_completion_client_with_explicit_settings.py index 613aa03000..afe73b428d 100644 --- a/python/samples/02-agents/providers/azure/openai_chat_completion_client_with_explicit_settings.py +++ b/python/samples/02-agents/providers/azure/openai_chat_completion_client_with_explicit_settings.py @@ -41,7 +41,7 @@ async def main() -> None: # authentication option. agent = Agent( client=OpenAIChatCompletionClient( - model=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + model=os.environ["AZURE_OPENAI_MODEL"], azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], credential=AzureCliCredential(), ), diff --git a/python/samples/02-agents/providers/azure/openai_client_basic.py b/python/samples/02-agents/providers/azure/openai_client_basic.py index 3029c03cda..0bb061ef92 100644 --- a/python/samples/02-agents/providers/azure/openai_client_basic.py +++ b/python/samples/02-agents/providers/azure/openai_client_basic.py @@ -38,7 +38,7 @@ async def non_streaming_example() -> None: agent = Agent( client=OpenAIChatClient( - model=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), + model=os.getenv("AZURE_OPENAI_MODEL"), azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), credential=AzureCliCredential(), @@ -60,7 +60,7 @@ async def streaming_example() -> None: agent = Agent( client=OpenAIChatClient( - model=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), + model=os.getenv("AZURE_OPENAI_MODEL"), azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), credential=AzureCliCredential(), diff --git a/python/samples/02-agents/providers/foundry/README.md b/python/samples/02-agents/providers/foundry/README.md index 80ddab2dcd..164032b752 100644 --- a/python/samples/02-agents/providers/foundry/README.md +++ b/python/samples/02-agents/providers/foundry/README.md @@ -45,4 +45,4 @@ This folder contains Azure AI Foundry and Foundry Local samples for Agent Framew ### Environment Variables -- `FOUNDRY_LOCAL_MODEL_ID`: Optional model alias/ID to use by default when `model_id` is not passed to `FoundryLocalClient`. +- `FOUNDRY_LOCAL_MODEL`: Optional model alias/ID to use by default when `model` is not passed to `FoundryLocalClient`. diff --git a/python/samples/02-agents/providers/ollama/README.md b/python/samples/02-agents/providers/ollama/README.md index 2a10ae2f57..2dca35a8fd 100644 --- a/python/samples/02-agents/providers/ollama/README.md +++ b/python/samples/02-agents/providers/ollama/README.md @@ -40,8 +40,8 @@ Set the following environment variables: - `OLLAMA_HOST`: The base URL for your Ollama server (optional, defaults to `http://localhost:11434`) - Example: `export OLLAMA_HOST="http://localhost:11434"` -- `OLLAMA_MODEL_ID`: The model name to use - - Example: `export OLLAMA_MODEL_ID="qwen2.5:8b"` +- `OLLAMA_MODEL`: The model name to use + - Example: `export OLLAMA_MODEL="qwen2.5:8b"` - Must be a model you have pulled with Ollama ### For OpenAI Client with Ollama (`ollama_with_openai_chat_client.py`) diff --git a/python/samples/02-agents/providers/ollama/ollama_agent_basic.py b/python/samples/02-agents/providers/ollama/ollama_agent_basic.py index 3652b069c4..a987c05398 100644 --- a/python/samples/02-agents/providers/ollama/ollama_agent_basic.py +++ b/python/samples/02-agents/providers/ollama/ollama_agent_basic.py @@ -17,7 +17,7 @@ This sample demonstrates implementing a Ollama agent with basic tool usage. Ensure to install Ollama and have a model running locally before running the sample Not all Models support function calling, to test function calling try llama3.2 or qwen3:4b -Set the model to use via the OLLAMA_MODEL_ID environment variable or modify the code below. +Set the model to use via the OLLAMA_MODEL environment variable or modify the code below. https://ollama.com/ """ diff --git a/python/samples/02-agents/providers/ollama/ollama_agent_reasoning.py b/python/samples/02-agents/providers/ollama/ollama_agent_reasoning.py index b23727311b..24defc5a8f 100644 --- a/python/samples/02-agents/providers/ollama/ollama_agent_reasoning.py +++ b/python/samples/02-agents/providers/ollama/ollama_agent_reasoning.py @@ -16,7 +16,7 @@ This sample demonstrates implementing a Ollama agent with reasoning. Ensure to install Ollama and have a model running locally before running the sample Not all Models support reasoning, to test reasoning try qwen3:8b -Set the model to use via the OLLAMA_MODEL_ID environment variable or modify the code below. +Set the model to use via the OLLAMA_MODEL environment variable or modify the code below. https://ollama.com/ """ diff --git a/python/samples/02-agents/providers/ollama/ollama_chat_client.py b/python/samples/02-agents/providers/ollama/ollama_chat_client.py index c92eaa0f55..15dbdf48aa 100644 --- a/python/samples/02-agents/providers/ollama/ollama_chat_client.py +++ b/python/samples/02-agents/providers/ollama/ollama_chat_client.py @@ -17,7 +17,7 @@ This sample demonstrates using the native Ollama Chat Client directly. Ensure to install Ollama and have a model running locally before running the sample. Not all Models support function calling, to test function calling try llama3.2 -Set the model to use via the OLLAMA_MODEL_ID environment variable or modify the code below. +Set the model to use via the OLLAMA_MODEL environment variable or modify the code below. https://ollama.com/ """ diff --git a/python/samples/02-agents/providers/ollama/ollama_chat_multimodal.py b/python/samples/02-agents/providers/ollama/ollama_chat_multimodal.py index bfeb7824fa..41e7c3aedd 100644 --- a/python/samples/02-agents/providers/ollama/ollama_chat_multimodal.py +++ b/python/samples/02-agents/providers/ollama/ollama_chat_multimodal.py @@ -16,7 +16,7 @@ This sample demonstrates implementing a Ollama agent with multimodal input capab Ensure to install Ollama and have a model running locally before running the sample Not all Models support multimodal input, to test multimodal input try gemma3:4b -Set the model to use via the OLLAMA_MODEL_ID environment variable or modify the code below. +Set the model to use via the OLLAMA_MODEL environment variable or modify the code below. https://ollama.com/ """ diff --git a/python/samples/02-agents/skills/code_defined_skill/README.md b/python/samples/02-agents/skills/code_defined_skill/README.md index 281580bcc7..c19a3c17d3 100644 --- a/python/samples/02-agents/skills/code_defined_skill/README.md +++ b/python/samples/02-agents/skills/code_defined_skill/README.md @@ -28,7 +28,7 @@ code_defined_skill/ Set the required environment variables in a `.env` file (see `python/.env.example`): - `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint -- `AZURE_OPENAI_DEPLOYMENT_NAME`: The name of your model deployment (defaults to `gpt-4o-mini`) +- `AZURE_OPENAI_MODEL`: The name of your model deployment (defaults to `gpt-4o-mini`) ### Authentication diff --git a/python/samples/02-agents/skills/file_based_skill/README.md b/python/samples/02-agents/skills/file_based_skill/README.md index 23a27d1c24..fa07b7e973 100644 --- a/python/samples/02-agents/skills/file_based_skill/README.md +++ b/python/samples/02-agents/skills/file_based_skill/README.md @@ -48,7 +48,7 @@ file_based_skill/ Set the required environment variables in a `.env` file (see `python/.env.example`): - `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint -- `AZURE_OPENAI_DEPLOYMENT_NAME`: The name of your model deployment (defaults to `gpt-4o-mini`) +- `AZURE_OPENAI_MODEL`: The name of your model deployment (defaults to `gpt-4o-mini`) ### Authentication diff --git a/python/samples/02-agents/skills/mixed_skills/README.md b/python/samples/02-agents/skills/mixed_skills/README.md index 0703ce5d20..d41f7dbaa9 100644 --- a/python/samples/02-agents/skills/mixed_skills/README.md +++ b/python/samples/02-agents/skills/mixed_skills/README.md @@ -61,7 +61,7 @@ Set environment variables (or create a `.env` file): ``` FOUNDRY_PROJECT_ENDPOINT=https://your-project.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o-mini +AZURE_OPENAI_MODEL=gpt-4o-mini ``` Authenticate with Azure CLI: diff --git a/python/samples/02-agents/skills/script_approval/README.md b/python/samples/02-agents/skills/script_approval/README.md index 81ef08c416..07dd37cb65 100644 --- a/python/samples/02-agents/skills/script_approval/README.md +++ b/python/samples/02-agents/skills/script_approval/README.md @@ -29,7 +29,7 @@ When `require_script_approval=True` is set, the agent pauses before executing an Set the required environment variables in a `.env` file (see `python/.env.example`): - `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint -- `AZURE_OPENAI_DEPLOYMENT_NAME`: The name of your model deployment (defaults to `gpt-4o-mini`) +- `AZURE_OPENAI_MODEL`: The name of your model deployment (defaults to `gpt-4o-mini`) ### Authentication diff --git a/python/samples/02-agents/typed_options.py b/python/samples/02-agents/typed_options.py index e6d5605ee8..65c2332892 100644 --- a/python/samples/02-agents/typed_options.py +++ b/python/samples/02-agents/typed_options.py @@ -38,7 +38,7 @@ async def demo_anthropic_chat_client() -> None: print("\n=== Anthropic ChatClient with TypedDict Options ===\n") # Create Anthropic client - client = AnthropicClient(model_id="claude-sonnet-4-5-20250929") + client = AnthropicClient(model="claude-sonnet-4-5-20250929") # Standard options work great: response = await client.get_response( @@ -53,14 +53,14 @@ async def demo_anthropic_chat_client() -> None: ) print(f"Anthropic Response: {response.text}") - print(f"Model used: {response.model_id}") + print(f"Model used: {response.model}") async def demo_anthropic_agent() -> None: """Demonstrate Agent with Anthropic client and typed options.""" print("\n=== Agent with Anthropic and Typed Options ===\n") - client = AnthropicClient(model_id="claude-sonnet-4-5-20250929") + client = AnthropicClient(model="claude-sonnet-4-5-20250929") # Create a typed agent for Anthropic - IDE knows Anthropic-specific options! agent = Agent( @@ -129,7 +129,7 @@ async def demo_openai_chat_client_reasoning_models() -> None: ) print(f"OpenAI Response: {response.text}") - print(f"Model used: {response.model_id}") + print(f"Model used: {response.model}") async def demo_openai_agent() -> None: diff --git a/python/samples/04-hosting/a2a/a2a_server.py b/python/samples/04-hosting/a2a/a2a_server.py index de3f361457..0bd0b29dc5 100644 --- a/python/samples/04-hosting/a2a/a2a_server.py +++ b/python/samples/04-hosting/a2a/a2a_server.py @@ -67,12 +67,12 @@ def main() -> None: # Validate environment project_endpoint = os.getenv("FOUNDRY_PROJECT_ENDPOINT") - deployment_name = os.getenv("FOUNDRY_MODEL") + model = os.getenv("FOUNDRY_MODEL") if not project_endpoint: print("Error: FOUNDRY_PROJECT_ENDPOINT environment variable is not set.") sys.exit(1) - if not deployment_name: + if not model: print("Error: FOUNDRY_MODEL environment variable is not set.") sys.exit(1) @@ -80,7 +80,7 @@ def main() -> None: credential = AzureCliCredential() client = FoundryChatClient( project_endpoint=project_endpoint, - model=deployment_name, + model=model, credential=credential, ) diff --git a/python/samples/04-hosting/azure_functions/02_multi_agent/function_app.py b/python/samples/04-hosting/azure_functions/02_multi_agent/function_app.py index 9771a27f70..e9e2cb05f3 100644 --- a/python/samples/04-hosting/azure_functions/02_multi_agent/function_app.py +++ b/python/samples/04-hosting/azure_functions/02_multi_agent/function_app.py @@ -7,7 +7,7 @@ Components used in this sample: - AgentFunctionApp to register multiple agents and expose dedicated HTTP endpoints. - Custom tool functions to demonstrate tool invocation from different agents. -Prerequisites: set `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_DEPLOYMENT_NAME`, and sign in with Azure CLI before starting the Functions host.""" +Prerequisites: set `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_MODEL`, and sign in with Azure CLI before starting the Functions host.""" import logging from typing import Any diff --git a/python/samples/04-hosting/azure_functions/11_workflow_parallel/.env.template b/python/samples/04-hosting/azure_functions/11_workflow_parallel/.env.template index bfea3f5279..f39a3a2933 100644 --- a/python/samples/04-hosting/azure_functions/11_workflow_parallel/.env.template +++ b/python/samples/04-hosting/azure_functions/11_workflow_parallel/.env.template @@ -10,4 +10,4 @@ TASKHUB_NAME=default # Azure OpenAI Configuration AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=your-deployment-name +AZURE_OPENAI_MODEL=your-deployment-name diff --git a/python/samples/04-hosting/azure_functions/11_workflow_parallel/README.md b/python/samples/04-hosting/azure_functions/11_workflow_parallel/README.md index 99afd35edb..e12cec0046 100644 --- a/python/samples/04-hosting/azure_functions/11_workflow_parallel/README.md +++ b/python/samples/04-hosting/azure_functions/11_workflow_parallel/README.md @@ -99,7 +99,7 @@ The sample can run locally without Azure Functions infrastructure using DevUI: ``` 2. Configure `.env` with your Azure OpenAI credentials (`AZURE_OPENAI_ENDPOINT` and - `AZURE_OPENAI_DEPLOYMENT_NAME`) + `AZURE_OPENAI_MODEL`) 3. Install dependencies: ```bash diff --git a/python/samples/04-hosting/azure_functions/11_workflow_parallel/function_app.py b/python/samples/04-hosting/azure_functions/11_workflow_parallel/function_app.py index 2ea10e8ce7..7deea4211c 100644 --- a/python/samples/04-hosting/azure_functions/11_workflow_parallel/function_app.py +++ b/python/samples/04-hosting/azure_functions/11_workflow_parallel/function_app.py @@ -21,7 +21,7 @@ Key architectural points: - Mixed agent/executor fan-outs execute concurrently Prerequisites: -- Configure `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_DEPLOYMENT_NAME` +- Configure `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_MODEL` - Sign in with Azure CLI (`az login`) for `AzureCliCredential` - Ensure Azurite and the Durable Task Scheduler emulator are running """ @@ -362,7 +362,7 @@ def _create_workflow() -> Workflow: credential = AzureCliCredential() chat_client = OpenAIChatCompletionClient( - model=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + model=os.environ["AZURE_OPENAI_MODEL"], api_key=get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default"), ) diff --git a/python/samples/04-hosting/azure_functions/11_workflow_parallel/local.settings.json.sample b/python/samples/04-hosting/azure_functions/11_workflow_parallel/local.settings.json.sample index 23140d3eec..5b65dd278f 100644 --- a/python/samples/04-hosting/azure_functions/11_workflow_parallel/local.settings.json.sample +++ b/python/samples/04-hosting/azure_functions/11_workflow_parallel/local.settings.json.sample @@ -6,6 +6,6 @@ "DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None", "TASKHUB_NAME": "default", "AZURE_OPENAI_ENDPOINT": "", - "AZURE_OPENAI_DEPLOYMENT_NAME": "" + "AZURE_OPENAI_MODEL": "" } } diff --git a/python/samples/04-hosting/durabletask/02_multi_agent/client.py b/python/samples/04-hosting/durabletask/02_multi_agent/client.py index 81933de8ee..693e6dcfe0 100644 --- a/python/samples/04-hosting/durabletask/02_multi_agent/client.py +++ b/python/samples/04-hosting/durabletask/02_multi_agent/client.py @@ -8,7 +8,7 @@ each with their own specialized capabilities and tools. Prerequisites: - The worker must be running with both agents registered -- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME when running the worker +- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_MODEL when running the worker - Sign in with Azure CLI for AzureCliCredential authentication - Durable Task Scheduler must be running """ diff --git a/python/samples/04-hosting/durabletask/02_multi_agent/sample.py b/python/samples/04-hosting/durabletask/02_multi_agent/sample.py index 4ef01fe400..e847abbd64 100644 --- a/python/samples/04-hosting/durabletask/02_multi_agent/sample.py +++ b/python/samples/04-hosting/durabletask/02_multi_agent/sample.py @@ -5,7 +5,7 @@ This sample demonstrates running both the worker and client in a single process for multiple agents with different tools. The worker registers two agents (WeatherAgent and MathAgent), each with their own specialized capabilities. Prerequisites: -- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME +- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_MODEL - Sign in with Azure CLI for AzureCliCredential authentication - Durable Task Scheduler must be running (e.g., using Docker) To run this sample: diff --git a/python/samples/04-hosting/durabletask/02_multi_agent/worker.py b/python/samples/04-hosting/durabletask/02_multi_agent/worker.py index 9183e9ee61..36bb96a555 100644 --- a/python/samples/04-hosting/durabletask/02_multi_agent/worker.py +++ b/python/samples/04-hosting/durabletask/02_multi_agent/worker.py @@ -7,7 +7,7 @@ with their own specialized tools. This demonstrates how to host multiple agents with different capabilities in a single worker process. Prerequisites: -- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME +- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_MODEL - Sign in with Azure CLI for AzureCliCredential authentication - Start a Durable Task Scheduler (e.g., using Docker) """ diff --git a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/README.md b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/README.md index caa3ca03f5..cc6879fc76 100644 --- a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/README.md +++ b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/README.md @@ -17,7 +17,7 @@ See the [README.md](../README.md) file in the parent directory for more informat This sample uses Azure OpenAI credentials: - `AZURE_OPENAI_ENDPOINT` -- `AZURE_OPENAI_DEPLOYMENT_NAME` +- `AZURE_OPENAI_MODEL` ## Running the Sample diff --git a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/client.py b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/client.py index 2eac694ed6..da42ad6d45 100644 --- a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/client.py +++ b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/client.py @@ -7,7 +7,7 @@ that uses conditional logic to either handle spam emails or draft professional r Prerequisites: - The worker must be running with both agents, orchestration, and activities registered -- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME +- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_MODEL - Sign in with Azure CLI for AzureCliCredential authentication - Durable Task Scheduler must be running """ diff --git a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/sample.py b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/sample.py index a00e075d4a..f243b2ccb7 100644 --- a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/sample.py +++ b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/sample.py @@ -10,7 +10,7 @@ The orchestration branches based on spam detection results, calling different activity functions to handle spam or send legitimate email responses. Prerequisites: -- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME +- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_MODEL - Sign in with Azure CLI for AzureCliCredential authentication - Durable Task Scheduler must be running (e.g., using Docker) diff --git a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/worker.py b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/worker.py index e9cda191f4..0b5f014873 100644 --- a/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/worker.py +++ b/python/samples/04-hosting/durabletask/06_multi_agent_orchestration_conditionals/worker.py @@ -7,7 +7,7 @@ orchestration function that routes execution based on spam detection results. Ac handle side effects (spam handling and email sending). Prerequisites: -- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME +- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_MODEL - Sign in with Azure CLI for AzureCliCredential authentication - Start a Durable Task Scheduler (e.g., using Docker) """ @@ -69,7 +69,7 @@ def create_spam_agent() -> "Agent": """ return Agent( client=OpenAIChatCompletionClient( - model=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + model=os.environ["AZURE_OPENAI_MODEL"], api_key=get_async_bearer_token_provider( AsyncAzureCliCredential(), "https://cognitiveservices.azure.com/.default" ), @@ -87,7 +87,7 @@ def create_email_agent() -> "Agent": """ return Agent( client=OpenAIChatCompletionClient( - model=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + model=os.environ["AZURE_OPENAI_MODEL"], api_key=get_async_bearer_token_provider( AsyncAzureCliCredential(), "https://cognitiveservices.azure.com/.default" ), diff --git a/python/samples/05-end-to-end/chatkit-integration/README.md b/python/samples/05-end-to-end/chatkit-integration/README.md index 365677eaad..5a8639fa51 100644 --- a/python/samples/05-end-to-end/chatkit-integration/README.md +++ b/python/samples/05-end-to-end/chatkit-integration/README.md @@ -177,7 +177,7 @@ pip install agent-framework-chatkit fastapi uvicorn azure-identity ```bash export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/" export AZURE_OPENAI_API_VERSION="2024-06-01" -export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o" +export AZURE_OPENAI_MODEL="gpt-4o" ``` 3. **Authenticate with Azure:** diff --git a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_agent_sample.py b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_agent_sample.py index 1135077f5c..7c8b306c11 100644 --- a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_agent_sample.py +++ b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_agent_sample.py @@ -10,7 +10,7 @@ See ``evaluate_tool_calls_sample.py`` for tool-call accuracy evaluation. Prerequisites: - An Azure AI Foundry project with a deployed model -- Set FOUNDRY_PROJECT_ENDPOINT and AZURE_AI_MODEL_DEPLOYMENT_NAME in .env +- Set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL in .env """ import asyncio diff --git a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_mixed_sample.py b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_mixed_sample.py index b15781e2bd..2f26eb2e3e 100644 --- a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_mixed_sample.py +++ b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_mixed_sample.py @@ -48,7 +48,7 @@ async def main() -> None: # 1. Set up the chat client chat_client = FoundryChatClient( project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME", "gpt-4o"), + model=os.environ.get("FOUNDRY_MODEL", "gpt-4o"), credential=AzureCliCredential(), ) diff --git a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_multiturn_sample.py b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_multiturn_sample.py index b28bba22c0..863011241f 100644 --- a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_multiturn_sample.py +++ b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_multiturn_sample.py @@ -11,7 +11,7 @@ a different aspect of agent behavior: Prerequisites: - An Azure AI Foundry project with a deployed model -- Set FOUNDRY_PROJECT_ENDPOINT and AZURE_AI_MODEL_DEPLOYMENT_NAME in .env +- Set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL in .env """ import asyncio @@ -94,7 +94,7 @@ def print_split(item: EvalItem, split: ConversationSplit = ConversationSplit.LAS async def main() -> None: chat_client = FoundryChatClient( project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME", "gpt-4o"), + model=os.environ.get("FOUNDRY_MODEL", "gpt-4o"), credential=AzureCliCredential(), ) diff --git a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_tool_calls_sample.py b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_tool_calls_sample.py index 50b084606b..ef51afc0c6 100644 --- a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_tool_calls_sample.py +++ b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_tool_calls_sample.py @@ -7,7 +7,7 @@ by using ``FoundryEvals.evaluate()`` with ``TOOL_CALL_ACCURACY``. Prerequisites: - An Azure AI Foundry project with a deployed model -- Set FOUNDRY_PROJECT_ENDPOINT and AZURE_AI_MODEL_DEPLOYMENT_NAME in .env +- Set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL in .env """ import asyncio @@ -39,7 +39,7 @@ def get_flight_price(origin: str, destination: str) -> str: async def main() -> None: chat_client = FoundryChatClient( project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME", "gpt-4o"), + model=os.environ.get("FOUNDRY_MODEL", "gpt-4o"), credential=AzureCliCredential(), ) diff --git a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_traces_sample.py b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_traces_sample.py index e0d4d07950..5a1ebeeb57 100644 --- a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_traces_sample.py +++ b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_traces_sample.py @@ -13,7 +13,7 @@ Prerequisites: - An Azure AI Foundry project with a deployed model - Response IDs from prior agent runs (for Pattern 1) - OTel traces exported to App Insights (for Pattern 2) -- Set FOUNDRY_PROJECT_ENDPOINT and AZURE_AI_MODEL_DEPLOYMENT_NAME in .env +- Set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL in .env """ import asyncio @@ -30,7 +30,7 @@ async def main() -> None: # 1. Set up the chat client chat_client = FoundryChatClient( project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME", "gpt-4o"), + model=os.environ.get("FOUNDRY_MODEL", "gpt-4o"), credential=AzureCliCredential(), ) diff --git a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_workflow_sample.py b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_workflow_sample.py index 5f0a7315dc..e2861324f6 100644 --- a/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_workflow_sample.py +++ b/python/samples/05-end-to-end/evaluation/foundry_evals/evaluate_workflow_sample.py @@ -11,7 +11,7 @@ breakdown in sub_results so you can identify which agent is underperforming. Prerequisites: - An Azure AI Foundry project with a deployed model -- Set FOUNDRY_PROJECT_ENDPOINT and AZURE_AI_MODEL_DEPLOYMENT_NAME in .env +- Set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL in .env """ import asyncio @@ -46,7 +46,7 @@ async def main() -> None: # 1. Set up the chat client client = FoundryChatClient( project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ.get("AZURE_AI_MODEL_DEPLOYMENT_NAME", "gpt-4o"), + model=os.environ.get("FOUNDRY_MODEL", "gpt-4o"), credential=AzureCliCredential(), ) diff --git a/python/samples/05-end-to-end/evaluation/red_teaming/.env.example b/python/samples/05-end-to-end/evaluation/red_teaming/.env.example index d74003f39b..584c630542 100644 --- a/python/samples/05-end-to-end/evaluation/red_teaming/.env.example +++ b/python/samples/05-end-to-end/evaluation/red_teaming/.env.example @@ -1,6 +1,6 @@ # Azure OpenAI Configuration (for the agent being tested) AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o +AZURE_OPENAI_MODEL=gpt-4o # AZURE_OPENAI_API_KEY=your-api-key-here # Azure AI Project Configuration (for red teaming) diff --git a/python/samples/05-end-to-end/evaluation/red_teaming/README.md b/python/samples/05-end-to-end/evaluation/red_teaming/README.md index bdd3dfcb72..c72713356b 100644 --- a/python/samples/05-end-to-end/evaluation/red_teaming/README.md +++ b/python/samples/05-end-to-end/evaluation/red_teaming/README.md @@ -43,7 +43,7 @@ Create a `.env` file in this directory or set these environment variables: ```bash # Azure OpenAI (for the agent being tested) AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o +AZURE_OPENAI_MODEL=gpt-4o # AZURE_OPENAI_API_KEY is optional if using Azure CLI authentication # Azure AI Project (for red teaming) diff --git a/python/samples/05-end-to-end/evaluation/red_teaming/red_team_agent_sample.py b/python/samples/05-end-to-end/evaluation/red_teaming/red_team_agent_sample.py index d0edf632d8..758a462dcb 100644 --- a/python/samples/05-end-to-end/evaluation/red_teaming/red_team_agent_sample.py +++ b/python/samples/05-end-to-end/evaluation/red_teaming/red_team_agent_sample.py @@ -51,7 +51,7 @@ async def main() -> None: credential = AzureCliCredential() # Create the agent # Constructor automatically reads from environment variables: - # AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_DEPLOYMENT_NAME, AZURE_OPENAI_API_KEY + # AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_MODEL, AZURE_OPENAI_API_KEY agent = Agent( client=FoundryChatClient(credential=credential), name="FinancialAdvisor", diff --git a/python/samples/05-end-to-end/hosted_agents/README.md b/python/samples/05-end-to-end/hosted_agents/README.md index 5ee8a7b1b2..d45b2f630c 100644 --- a/python/samples/05-end-to-end/hosted_agents/README.md +++ b/python/samples/05-end-to-end/hosted_agents/README.md @@ -76,7 +76,7 @@ Example `.env` for Azure OpenAI samples: ```dotenv AZURE_OPENAI_ENDPOINT=https://.openai.azure.com/ -AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4.1 +AZURE_OPENAI_MODEL=gpt-4.1 ``` Example `.env` for Foundry project samples: diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml index ce59158393..6e46adcaed 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_hosted_mcp/agent.yaml @@ -22,7 +22,7 @@ template: environment_variables: - name: AZURE_OPENAI_ENDPOINT value: ${AZURE_OPENAI_ENDPOINT} - - name: AZURE_OPENAI_DEPLOYMENT_NAME + - name: AZURE_OPENAI_MODEL value: "{{chat}}" resources: - kind: model diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/.env.sample b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/.env.sample index 7a7d4d5ec3..67bcea72f3 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/.env.sample +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/.env.sample @@ -1,3 +1,3 @@ # IMPORTANT: Never commit .env to version control - add it to .gitignore -PROJECT_ENDPOINT= -MODEL_DEPLOYMENT_NAME= \ No newline at end of file +FOUNDRY_PROJECT_ENDPOINT= +FOUNDRY_MODEL= \ No newline at end of file diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/README.md b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/README.md index 41fa3660fa..50efdcb7a4 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/README.md +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/README.md @@ -59,24 +59,24 @@ Before running this sample, ensure you have: Set the following environment variables (matching `agent.yaml`): -- `PROJECT_ENDPOINT` - Your Microsoft Foundry project endpoint URL (required) -- `MODEL_DEPLOYMENT_NAME` - The deployment name for your chat model (defaults to `gpt-4.1-mini`) +- `FOUNDRY_PROJECT_ENDPOINT` - Your Microsoft Foundry project endpoint URL (required) +- `FOUNDRY_MODEL` - The deployment name for your chat model (defaults to `gpt-4.1-mini`) This sample loads environment variables from a local `.env` file if present. Create a `.env` file in this directory with the following content: ``` -PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/ -MODEL_DEPLOYMENT_NAME=gpt-4.1-mini +FOUNDRY_PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/ +FOUNDRY_MODEL=gpt-4.1-mini ``` Or set them via PowerShell: ```powershell # Replace with your actual values -$env:PROJECT_ENDPOINT="https://.services.ai.azure.com/api/projects/" -$env:MODEL_DEPLOYMENT_NAME="gpt-4.1-mini" +$env:FOUNDRY_PROJECT_ENDPOINT="https://.services.ai.azure.com/api/projects/" +$env:FOUNDRY_MODEL="gpt-4.1-mini" ``` ### Running the Sample diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/agent.yaml b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/agent.yaml index 159b31996d..d18fafc374 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/agent.yaml +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/agent.yaml @@ -21,7 +21,7 @@ protocols: - protocol: responses version: v1 environment_variables: - - name: PROJECT_ENDPOINT - value: ${PROJECT_ENDPOINT} - - name: MODEL_DEPLOYMENT_NAME - value: ${MODEL_DEPLOYMENT_NAME} \ No newline at end of file + - name: FOUNDRY_PROJECT_ENDPOINT + value: ${FOUNDRY_PROJECT_ENDPOINT} + - name: FOUNDRY_MODEL + value: ${FOUNDRY_MODEL} \ No newline at end of file diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/main.py b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/main.py index 880162586b..3bdecb5100 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/main.py +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_local_tools/main.py @@ -18,10 +18,8 @@ from azure.identity.aio import AzureCliCredential, ManagedIdentityCredential # Configure these for your Foundry project # Read the explicit variables present in the .env file -PROJECT_ENDPOINT = os.getenv("PROJECT_ENDPOINT") # e.g., "https://.services.ai.azure.com" -MODEL_DEPLOYMENT_NAME = os.getenv( - "MODEL_DEPLOYMENT_NAME", "gpt-4.1-mini" -) # Your model deployment name e.g., "gpt-4.1-mini" +FOUNDRY_PROJECT_ENDPOINT = os.getenv("FOUNDRY_PROJECT_ENDPOINT") # e.g., "https://.services.ai.azure.com" +FOUNDRY_MODEL = os.getenv("FOUNDRY_MODEL", "gpt-4.1-mini") # Your model deployment name e.g., "gpt-4.1-mini" # Simulated hotel data for Seattle @@ -116,8 +114,8 @@ async def main(): """Main function to run the agent as a web server.""" async with get_credential() as credential: client = FoundryChatClient( - project_endpoint=PROJECT_ENDPOINT, - model=MODEL_DEPLOYMENT_NAME, + project_endpoint=FOUNDRY_PROJECT_ENDPOINT, + model=FOUNDRY_MODEL, credential=credential, ) agent = Agent( diff --git a/python/samples/05-end-to-end/hosted_agents/agent_with_text_search_rag/agent.yaml b/python/samples/05-end-to-end/hosted_agents/agent_with_text_search_rag/agent.yaml index a54917bba5..13938f6a51 100644 --- a/python/samples/05-end-to-end/hosted_agents/agent_with_text_search_rag/agent.yaml +++ b/python/samples/05-end-to-end/hosted_agents/agent_with_text_search_rag/agent.yaml @@ -25,7 +25,7 @@ template: environment_variables: - name: AZURE_OPENAI_ENDPOINT value: ${AZURE_OPENAI_ENDPOINT} - - name: AZURE_OPENAI_DEPLOYMENT_NAME + - name: AZURE_OPENAI_MODEL value: "{{chat}}" resources: - kind: model diff --git a/python/samples/05-end-to-end/hosted_agents/agents_in_workflow/agent.yaml b/python/samples/05-end-to-end/hosted_agents/agents_in_workflow/agent.yaml index bd2824276a..82f4d9e887 100644 --- a/python/samples/05-end-to-end/hosted_agents/agents_in_workflow/agent.yaml +++ b/python/samples/05-end-to-end/hosted_agents/agents_in_workflow/agent.yaml @@ -20,7 +20,7 @@ template: environment_variables: - name: AZURE_OPENAI_ENDPOINT value: ${AZURE_OPENAI_ENDPOINT} - - name: AZURE_OPENAI_DEPLOYMENT_NAME + - name: AZURE_OPENAI_MODEL value: "{{chat}}" resources: - kind: model diff --git a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/.env.sample b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/.env.sample index 7a7d4d5ec3..67bcea72f3 100644 --- a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/.env.sample +++ b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/.env.sample @@ -1,3 +1,3 @@ # IMPORTANT: Never commit .env to version control - add it to .gitignore -PROJECT_ENDPOINT= -MODEL_DEPLOYMENT_NAME= \ No newline at end of file +FOUNDRY_PROJECT_ENDPOINT= +FOUNDRY_MODEL= \ No newline at end of file diff --git a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/README.md b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/README.md index f4181f6e6b..8a9464f7b5 100644 --- a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/README.md +++ b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/README.md @@ -56,24 +56,24 @@ Before running this sample, ensure you have: Set the following environment variables (matching `agent.yaml`): -- `PROJECT_ENDPOINT` - Your Microsoft Foundry project endpoint URL (required) -- `MODEL_DEPLOYMENT_NAME` - The deployment name for your chat model (defaults to `gpt-4.1-mini`) +- `FOUNDRY_PROJECT_ENDPOINT` - Your Microsoft Foundry project endpoint URL (required) +- `FOUNDRY_MODEL` - The deployment name for your chat model (defaults to `gpt-4.1-mini`) This sample loads environment variables from a local `.env` file if present. Create a `.env` file in this directory with the following content: ``` -PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/ -MODEL_DEPLOYMENT_NAME=gpt-4.1-mini +FOUNDRY_PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/ +FOUNDRY_MODEL=gpt-4.1-mini ``` Or set them via PowerShell: ```powershell # Replace with your actual values -$env:PROJECT_ENDPOINT="https://.services.ai.azure.com/api/projects/" -$env:MODEL_DEPLOYMENT_NAME="gpt-4.1-mini" +$env:FOUNDRY_PROJECT_ENDPOINT="https://.services.ai.azure.com/api/projects/" +$env:FOUNDRY_MODEL="gpt-4.1-mini" ``` ### Running the Sample diff --git a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/agent.yaml b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/agent.yaml index 9a5e63b83f..36e08b7e77 100644 --- a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/agent.yaml +++ b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/agent.yaml @@ -18,7 +18,7 @@ protocols: - protocol: responses version: v1 environment_variables: - - name: PROJECT_ENDPOINT - value: ${PROJECT_ENDPOINT} - - name: MODEL_DEPLOYMENT_NAME - value: ${MODEL_DEPLOYMENT_NAME} \ No newline at end of file + - name: FOUNDRY_PROJECT_ENDPOINT + value: ${FOUNDRY_PROJECT_ENDPOINT} + - name: FOUNDRY_MODEL + value: ${FOUNDRY_MODEL} \ No newline at end of file diff --git a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/main.py b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/main.py index 757bad4f26..ff42f7d6dc 100644 --- a/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/main.py +++ b/python/samples/05-end-to-end/hosted_agents/writer_reviewer_agents_in_workflow/main.py @@ -14,12 +14,10 @@ load_dotenv(override=True) # Configure these for your Foundry project # Read the explicit variables present in the .env file -PROJECT_ENDPOINT = os.getenv( - "PROJECT_ENDPOINT" +FOUNDRY_PROJECT_ENDPOINT = os.getenv( + "FOUNDRY_PROJECT_ENDPOINT" ) # e.g., "https://.services.ai.azure.com/api/projects/" -MODEL_DEPLOYMENT_NAME = os.getenv( - "MODEL_DEPLOYMENT_NAME", "gpt-4.1-mini" -) # Your model deployment name e.g., "gpt-4.1-mini" +FOUNDRY_MODEL = os.getenv("FOUNDRY_MODEL", "gpt-4.1-mini") # Your model deployment name e.g., "gpt-4.1-mini" def get_credential(): @@ -31,8 +29,8 @@ def get_credential(): async def create_agents(): async with get_credential() as credential: client = FoundryChatClient( - project_endpoint=PROJECT_ENDPOINT, - model=MODEL_DEPLOYMENT_NAME, + project_endpoint=FOUNDRY_PROJECT_ENDPOINT, + model=FOUNDRY_MODEL, credential=credential, ) writer = Agent( @@ -60,8 +58,8 @@ async def main() -> None: The writer and reviewer multi-agent workflow. Environment variables required: - - PROJECT_ENDPOINT: Your Microsoft Foundry project endpoint - - MODEL_DEPLOYMENT_NAME: Your Microsoft Foundry model deployment name + - FOUNDRY_PROJECT_ENDPOINT: Your Microsoft Foundry project endpoint + - FOUNDRY_MODEL: Your Microsoft Foundry model deployment name """ async with create_agents() as (writer, reviewer): diff --git a/python/samples/05-end-to-end/purview_agent/README.md b/python/samples/05-end-to-end/purview_agent/README.md index 3d13478616..1cdb7e3ef4 100644 --- a/python/samples/05-end-to-end/purview_agent/README.md +++ b/python/samples/05-end-to-end/purview_agent/README.md @@ -18,7 +18,7 @@ This getting-started sample shows how to attach Microsoft Purview policy evaluat | Variable | Required | Purpose | |----------|----------|---------| | `AZURE_OPENAI_ENDPOINT` | Yes | Azure OpenAI endpoint (https://.openai.azure.com) | -| `AZURE_OPENAI_DEPLOYMENT_NAME` | Optional | Model deployment name (defaults inside SDK if omitted) | +| `AZURE_OPENAI_MODEL` | Optional | Model deployment name (defaults inside SDK if omitted) | | `PURVIEW_CLIENT_APP_ID` | Yes* | Client (application) ID used for Purview authentication | | `PURVIEW_USE_CERT_AUTH` | Optional (`true`/`false`) | Switch between certificate and interactive auth | | `PURVIEW_TENANT_ID` | Yes (when cert auth on) | Tenant ID for certificate authentication | diff --git a/python/samples/05-end-to-end/purview_agent/sample_purview_agent.py b/python/samples/05-end-to-end/purview_agent/sample_purview_agent.py index 369e39655b..689d4e6e46 100644 --- a/python/samples/05-end-to-end/purview_agent/sample_purview_agent.py +++ b/python/samples/05-end-to-end/purview_agent/sample_purview_agent.py @@ -12,7 +12,7 @@ Note: Caching is automatic and enabled by default. Environment variables: - AZURE_OPENAI_ENDPOINT (required) -- AZURE_OPENAI_DEPLOYMENT_NAME (optional, defaults to gpt-4o-mini) +- AZURE_OPENAI_MODEL (optional, defaults to gpt-4o-mini) - PURVIEW_CLIENT_APP_ID (required) - PURVIEW_USE_CERT_AUTH (optional, set to "true" for certificate auth) - PURVIEW_TENANT_ID (required if certificate auth) @@ -143,7 +143,7 @@ async def run_with_agent_middleware() -> None: print("Skipping run: AZURE_OPENAI_ENDPOINT not set") return - deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o-mini") + deployment = os.environ.get("AZURE_OPENAI_MODEL", "gpt-4o-mini") user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID") client = FoundryChatClient(model=deployment, endpoint=endpoint, credential=AzureCliCredential()) @@ -179,7 +179,7 @@ async def run_with_chat_middleware() -> None: print("Skipping chat middleware run: AZURE_OPENAI_ENDPOINT not set") return - deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", default="gpt-4o-mini") + deployment = os.environ.get("AZURE_OPENAI_MODEL", default="gpt-4o-mini") user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID") client = FoundryChatClient( @@ -229,7 +229,7 @@ async def run_with_custom_cache_provider() -> None: print("Skipping custom cache provider run: AZURE_OPENAI_ENDPOINT not set") return - deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o-mini") + deployment = os.environ.get("AZURE_OPENAI_MODEL", "gpt-4o-mini") user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID") client = FoundryChatClient(model=deployment, endpoint=endpoint, credential=AzureCliCredential()) @@ -269,7 +269,7 @@ async def run_with_custom_cache_provider() -> None: print("Skipping default cache run: AZURE_OPENAI_ENDPOINT not set") return - deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o-mini") + deployment = os.environ.get("AZURE_OPENAI_MODEL", "gpt-4o-mini") user_id = os.environ.get("PURVIEW_DEFAULT_USER_ID") client = FoundryChatClient(model=deployment, endpoint=endpoint, credential=AzureCliCredential()) diff --git a/python/samples/05-end-to-end/workflow_evaluation/create_workflow.py b/python/samples/05-end-to-end/workflow_evaluation/create_workflow.py index f0dbb504cc..053011f8ea 100644 --- a/python/samples/05-end-to-end/workflow_evaluation/create_workflow.py +++ b/python/samples/05-end-to-end/workflow_evaluation/create_workflow.py @@ -145,14 +145,14 @@ class ResearchLead(Executor): async def run_workflow_with_response_tracking( - query: str, client: FoundryChatClient | None = None, deployment_name: str | None = None + query: str, client: FoundryChatClient | None = None, model: str | None = None ) -> dict: """Run multi-agent workflow and track conversation IDs, response IDs, and interaction sequence. Args: query: The user query to process through the multi-agent workflow client: Optional FoundryChatClient instance - deployment_name: Optional model deployment name for the workflow agents + model: Optional model for the workflow agents Returns: Dictionary containing interaction sequence, conversation/response IDs, and conversation analysis @@ -166,7 +166,7 @@ async def run_workflow_with_response_tracking( ) async with project_client: - client = FoundryChatClient(project_client=project_client, model=deployment_name) + client = FoundryChatClient(project_client=project_client, model=model) return await _run_workflow_with_client(query, client) except Exception as e: print(f"Error during workflow execution: {e}") @@ -347,11 +347,11 @@ def _track_agent_ids(event, agent, response_ids, conversation_ids): conversation_ids[agent].append(raw.conversation_id) -async def create_and_run_workflow(deployment_name: str | None = None): +async def create_and_run_workflow(model: str | None = None): """Run the workflow evaluation and display results. Args: - deployment_name: Optional model deployment name for the workflow agents + model: Optional model for the workflow agents Returns: Dictionary containing agents data with conversation IDs, response IDs, and query information @@ -365,7 +365,7 @@ async def create_and_run_workflow(deployment_name: str | None = None): query = example_queries[0] print(f"Query: {query}\n") - result = await run_workflow_with_response_tracking(query, model=deployment_name) + result = await run_workflow_with_response_tracking(query, model=model) # Create output data structure output_data = {"agents": {}, "query": result["query"], "output": result.get("output", "")} diff --git a/python/samples/05-end-to-end/workflow_evaluation/run_evaluation.py b/python/samples/05-end-to-end/workflow_evaluation/run_evaluation.py index f4bc8ebb85..e246710b41 100644 --- a/python/samples/05-end-to-end/workflow_evaluation/run_evaluation.py +++ b/python/samples/05-end-to-end/workflow_evaluation/run_evaluation.py @@ -46,11 +46,11 @@ def print_section(title: str): print(f"{'=' * 80}") -async def run_workflow(deployment_name: str | None = None) -> dict[str, Any]: +async def run_workflow(model: str | None = None) -> dict[str, Any]: """Execute the multi-agent travel planning workflow. Args: - deployment_name: Optional model deployment name for the workflow agents + model: Optional model for the workflow agents Returns: Dictionary containing workflow data with agent response IDs @@ -58,7 +58,7 @@ async def run_workflow(deployment_name: str | None = None) -> dict[str, Any]: print("Executing multi-agent travel planning workflow...") print("This may take a few minutes...") - workflow_data = await create_and_run_workflow(model=deployment_name) + workflow_data = await create_and_run_workflow(model=model) print("Workflow execution completed") return workflow_data @@ -97,9 +97,9 @@ def fetch_agent_responses(openai_client: OpenAI, workflow_data: dict[str, Any], print(f" Error: {e}") -def create_evaluation(openai_client: OpenAI, deployment_name: str | None = "gpt-5.2") -> EvalCreateResponse: +def create_evaluation(openai_client: OpenAI, model: str | None = "gpt-5.2") -> EvalCreateResponse: """Create evaluation with multiple evaluators.""" - deployment_name = os.environ.get("FOUNDRY_MODEL", deployment_name) + model = os.environ.get("FOUNDRY_MODEL", model) data_source_config = {"type": "azure_ai_source", "scenario": "responses"} testing_criteria = [ @@ -107,25 +107,25 @@ def create_evaluation(openai_client: OpenAI, deployment_name: str | None = "gpt- "type": "azure_ai_evaluator", "name": "relevance", "evaluator_name": "builtin.relevance", - "initialization_parameters": {"deployment_name": deployment_name}, + "initialization_parameters": {"deployment_name": model}, }, { "type": "azure_ai_evaluator", "name": "groundedness", "evaluator_name": "builtin.groundedness", - "initialization_parameters": {"deployment_name": deployment_name}, + "initialization_parameters": {"deployment_name": model}, }, { "type": "azure_ai_evaluator", "name": "tool_call_accuracy", "evaluator_name": "builtin.tool_call_accuracy", - "initialization_parameters": {"deployment_name": deployment_name}, + "initialization_parameters": {"deployment_name": model}, }, { "type": "azure_ai_evaluator", "name": "tool_output_utilization", "evaluator_name": "builtin.tool_output_utilization", - "initialization_parameters": {"deployment_name": deployment_name}, + "initialization_parameters": {"deployment_name": model}, }, ] diff --git a/python/samples/README.md b/python/samples/README.md index 4e178c2a78..fc55a4157e 100644 --- a/python/samples/README.md +++ b/python/samples/README.md @@ -91,11 +91,11 @@ variable. | package | class | env var | example value | | --- | --- | --- | --- | | `agent-framework-anthropic` | `AnthropicClient` | `ANTHROPIC_API_KEY` | `sk-ant-api03-...` | -| `agent-framework-anthropic` | `AnthropicClient` | `ANTHROPIC_CHAT_MODEL_ID` | `claude-sonnet-4-5-20250929` | +| `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_ID` | `text-embedding-3-small` | -| `agent-framework-azure-ai` | `AzureAIInferenceEmbeddingClient` | `AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID` | `Cohere-embed-v3-english` | +| `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-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` | @@ -105,9 +105,9 @@ variable. | `agent-framework-azure-cosmos` | `CosmosHistoryProvider` | `AZURE_COSMOS_CONTAINER_NAME` | `messages` | | `agent-framework-azure-cosmos` | `CosmosHistoryProvider` | `AZURE_COSMOS_KEY` | `C2F...==` | | `agent-framework-bedrock` | `BedrockChatClient` | `BEDROCK_REGION` | `us-east-1` | -| `agent-framework-bedrock` | `BedrockChatClient` | `BEDROCK_CHAT_MODEL_ID` | `anthropic.claude-3-5-sonnet-20241022-v2:0` | +| `agent-framework-bedrock` | `BedrockChatClient` | `BEDROCK_CHAT_MODEL` | `anthropic.claude-3-5-sonnet-20241022-v2:0` | | `agent-framework-bedrock` | `BedrockEmbeddingClient` | `BEDROCK_REGION` | `us-east-1` | -| `agent-framework-bedrock` | `BedrockEmbeddingClient` | `BEDROCK_EMBEDDING_MODEL_ID` | `amazon.titan-embed-text-v2:0` | +| `agent-framework-bedrock` | `BedrockEmbeddingClient` | `BEDROCK_EMBEDDING_MODEL` | `amazon.titan-embed-text-v2:0` | | `agent-framework-bedrock` | `BedrockChatClient / BedrockEmbeddingClient` | `AWS_ACCESS_KEY_ID` | `AKIAIOSFODNN7EXAMPLE` | | `agent-framework-bedrock` | `BedrockChatClient / BedrockEmbeddingClient` | `AWS_SECRET_ACCESS_KEY` | `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY` | | `agent-framework-bedrock` | `BedrockChatClient / BedrockEmbeddingClient` | `AWS_SESSION_TOKEN` | `IQoJb3JpZ2luX2VjEO7//////////wEaCXVzLXdlc3QtMiJHMEUCIQD...` | @@ -141,7 +141,7 @@ variable. | `agent-framework-github-copilot` | `GitHubCopilotAgent` | `GITHUB_COPILOT_LOG_LEVEL` | `info` | | `agent-framework-mem0` | `agent_framework_mem0 package import` | `MEM0_TELEMETRY` | `false` | | `agent-framework-ollama` | `OllamaChatClient` | `OLLAMA_HOST` | `http://localhost:11434` | -| `agent-framework-ollama` | `OllamaChatClient` | `OLLAMA_MODEL_ID` | `llama3.1:8b` | +| `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` | @@ -153,10 +153,10 @@ variable. | `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_API_KEY` | `sk-azure-...` | | `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_DEPLOYMENT_NAME` | `gpt-4o` | -| `agent-framework-openai` | `OpenAIChatClient` | `AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME` | `gpt-4.1` | -| `agent-framework-openai` | `OpenAIChatCompletionClient` | `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` | `gpt-4o-mini` | -| `agent-framework-openai` | `OpenAIEmbeddingClient` | `AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME` | `text-embedding-3-large` | +| `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` | `OpenAIEmbeddingClient` | `AZURE_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-large` | | `agent-framework-openai` | `OpenAIChatClient / OpenAIChatCompletionClient / OpenAIEmbeddingClient` | `AZURE_OPENAI_RESOURCE_URL` | `https://cognitiveservices.azure.com/` | `agent-framework-openai` supports the Azure OpenAI client-specific deployment aliases listed above; keep diff --git a/python/samples/semantic-kernel-migration/openai_responses/01_basic_responses_agent.py b/python/samples/semantic-kernel-migration/openai_responses/01_basic_responses_agent.py index d74487d1e8..37f002ef22 100644 --- a/python/samples/semantic-kernel-migration/openai_responses/01_basic_responses_agent.py +++ b/python/samples/semantic-kernel-migration/openai_responses/01_basic_responses_agent.py @@ -23,12 +23,12 @@ async def run_semantic_kernel() -> None: from semantic_kernel.connectors.ai.open_ai import OpenAISettings openai_settings = OpenAISettings() - assert openai_settings.responses_model_id is not None, "Responses model ID must be set in OpenAISettings" + assert openai_settings.responses_model is not None, "Responses model ID must be set in OpenAISettings" client = OpenAIResponsesAgent.create_client() # SK response agents wrap OpenAI's hosted Responses API. agent = OpenAIResponsesAgent( - ai_model_id=openai_settings.responses_model_id, + ai_model=openai_settings.responses_model, client=client, instructions="Answer in one concise sentence.", name="Expert", diff --git a/python/samples/semantic-kernel-migration/openai_responses/02_responses_agent_with_tool.py b/python/samples/semantic-kernel-migration/openai_responses/02_responses_agent_with_tool.py index 01b783aff9..306aa68a23 100644 --- a/python/samples/semantic-kernel-migration/openai_responses/02_responses_agent_with_tool.py +++ b/python/samples/semantic-kernel-migration/openai_responses/02_responses_agent_with_tool.py @@ -29,12 +29,12 @@ async def run_semantic_kernel() -> None: return a + b openai_settings = OpenAISettings() - assert openai_settings.responses_model_id is not None, "Responses model ID must be set in OpenAISettings" + assert openai_settings.responses_model is not None, "Responses model ID must be set in OpenAISettings" client = OpenAIResponsesAgent.create_client() # Plugins advertise callable tools to the Responses agent. agent = OpenAIResponsesAgent( - ai_model_id=openai_settings.responses_model_id, + ai_model=openai_settings.responses_model, client=client, instructions="Use the add tool when math is required.", name="MathExpert", diff --git a/python/samples/semantic-kernel-migration/openai_responses/03_responses_agent_structured_output.py b/python/samples/semantic-kernel-migration/openai_responses/03_responses_agent_structured_output.py index cbfbf470a0..133d3b079c 100644 --- a/python/samples/semantic-kernel-migration/openai_responses/03_responses_agent_structured_output.py +++ b/python/samples/semantic-kernel-migration/openai_responses/03_responses_agent_structured_output.py @@ -30,12 +30,12 @@ async def run_semantic_kernel() -> None: from semantic_kernel.connectors.ai.open_ai import OpenAISettings openai_settings = OpenAISettings() - assert openai_settings.responses_model_id is not None, "Responses model ID must be set in OpenAISettings" + assert openai_settings.responses_model is not None, "Responses model ID must be set in OpenAISettings" client = OpenAIResponsesAgent.create_client() # response_format requests schema-constrained output from the model. agent = OpenAIResponsesAgent( - ai_model_id=openai_settings.responses_model_id, + ai_model=openai_settings.responses_model, client=client, instructions="Return launch briefs as structured JSON.", name="ProductMarketer", diff --git a/python/samples/semantic-kernel-migration/orchestrations/magentic.py b/python/samples/semantic-kernel-migration/orchestrations/magentic.py index b5360e2130..dcf7b1af33 100644 --- a/python/samples/semantic-kernel-migration/orchestrations/magentic.py +++ b/python/samples/semantic-kernel-migration/orchestrations/magentic.py @@ -54,15 +54,15 @@ async def build_semantic_kernel_agents() -> list[ChatCompletionAgent | OpenAIAss instructions=( "You are a Researcher. You find information without additional computation or quantitative analysis." ), - service=OpenAIChatCompletion(ai_model_id="gpt-4o-mini-search-preview"), + service=OpenAIChatCompletion(ai_model="gpt-4o-mini-search-preview"), ) client = OpenAIAssistantAgent.create_client() code_interpreter_tool, code_interpreter_tool_resources = OpenAIAssistantAgent.configure_code_interpreter_tool() openai_settings = OpenAISettings() - model_id = openai_settings.chat_model_id if openai_settings.chat_model_id else "gpt-5" + model = openai_settings.chat_model if openai_settings.chat_model else "gpt-5" definition = await client.beta.assistants.create( # pyright: ignore[reportDeprecated] - model=model_id, + model=model, name="CoderAgent", description="A helpful assistant that writes and executes code to process and analyze data.", instructions="You solve questions using code. Please provide detailed analysis and computation process.",