diff --git a/.github/workflows/python-test-coverage-report.yml b/.github/workflows/python-test-coverage-report.yml
index f5f5f8eb03..dbe5b9e9c0 100644
--- a/.github/workflows/python-test-coverage-report.yml
+++ b/.github/workflows/python-test-coverage-report.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Download coverage report
- uses: actions/download-artifact@v7
+ uses: actions/download-artifact@v8
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
run-id: ${{ github.event.workflow_run.id }}
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 576d2c5c54..af7ca9f0be 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -309,7 +309,6 @@
-
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj
index 1afc7a7cec..a56157fe9d 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj
@@ -36,10 +36,10 @@
-
+
-
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj
index c0e14e74b8..4e46f10c11 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj
@@ -1,4 +1,4 @@
-
+
Exe
@@ -35,11 +35,10 @@
-
-
+
+
-
-
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs
index 8559269dff..b7b610b663 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs
+++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs
@@ -31,8 +31,7 @@ AITool mcpTool = new HostedMcpServerTool(serverName: "microsoft_learn", serverAd
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
- .GetResponsesClient()
- .AsIChatClient(deploymentName)
+ .GetResponsesClient(deploymentName)
.AsAIAgent(
instructions: "You answer questions by searching the Microsoft Learn content only.",
name: "MicrosoftLearnAgent",
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj
index ccda3156e5..b7970f8c5f 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj
@@ -36,11 +36,11 @@
-
-
+
+
-
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj
index 19e5015912..7789abd315 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj
@@ -1,4 +1,4 @@
-
+
Exe
@@ -35,10 +35,10 @@
-
+
-
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj
deleted file mode 100644
index 19e5015912..0000000000
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
- Exe
- net10.0
-
- enable
- enable
-
-
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Dockerfile b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Dockerfile
deleted file mode 100644
index c9f39f9574..0000000000
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Build the application
-FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
-WORKDIR /src
-
-# Copy files from the current directory on the host to the working directory in the container
-COPY . .
-
-RUN dotnet restore
-RUN dotnet build -c Release --no-restore
-RUN dotnet publish -c Release --no-build -o /app -f net10.0
-
-# Run the application
-FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
-WORKDIR /app
-
-# Copy everything needed to run the app from the "build" stage.
-COPY --from=build /app .
-
-EXPOSE 8088
-ENTRYPOINT ["dotnet", "AgentWithTools.dll"]
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs
deleted file mode 100644
index f564a0d8d3..0000000000
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-// This sample demonstrates how to use Foundry tools (MCP and code interpreter)
-// with an AI agent hosted using the Azure AI AgentServer SDK.
-
-using Azure.AI.AgentServer.AgentFramework.Extensions;
-using Azure.AI.OpenAI;
-using Azure.Identity;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
-
-string openAiEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
-string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
-string toolConnectionId = Environment.GetEnvironmentVariable("MCP_TOOL_CONNECTION_ID") ?? throw new InvalidOperationException("MCP_TOOL_CONNECTION_ID is not set.");
-
-// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
-// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
-// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
-DefaultAzureCredential credential = new();
-
-IChatClient chatClient = new AzureOpenAIClient(new Uri(openAiEndpoint), credential)
- .GetChatClient(deploymentName)
- .AsIChatClient()
- .AsBuilder()
- .UseFoundryTools(new { type = "mcp", project_connection_id = toolConnectionId }, new { type = "code_interpreter" })
- .UseOpenTelemetry(sourceName: "Agents", configure: (cfg) => cfg.EnableSensitiveData = true)
- .Build();
-
-AIAgent agent = chatClient.AsAIAgent(
- name: "AgentWithTools",
- instructions: @"You are a helpful assistant with access to tools for fetching Microsoft documentation.
-
- IMPORTANT: When the user asks about Microsoft Learn articles or documentation:
- 1. You MUST use the microsoft_docs_fetch tool to retrieve the actual content
- 2. Do NOT rely on your training data
- 3. Always fetch the latest information from the provided URL
-
- Available tools:
- - microsoft_docs_fetch: Fetches and converts Microsoft Learn documentation
- - microsoft_docs_search: Searches Microsoft/Azure documentation
- - microsoft_code_sample_search: Searches for code examples")
- .AsBuilder()
- .UseOpenTelemetry(sourceName: "Agents", configure: (cfg) => cfg.EnableSensitiveData = true)
- .Build();
-
-await agent.RunAIAgentAsync(telemetrySourceName: "Agents");
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md
deleted file mode 100644
index 55333f9940..0000000000
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# What this sample demonstrates
-
-This sample demonstrates how to use Foundry tools with an AI agent via the `UseFoundryTools` extension. The agent is configured with two tool types: an MCP (Model Context Protocol) connection for fetching Microsoft Learn documentation and a code interpreter for running code when needed.
-
-Key features:
-
-- Configuring Foundry tools using `UseFoundryTools` with MCP and code interpreter
-- Connecting to an external MCP tool via a Foundry project connection
-- Using `DefaultAzureCredential` for Azure authentication
-- OpenTelemetry instrumentation for both the chat client and agent
-
-> For common prerequisites and setup instructions, see the [Hosted Agent Samples README](../README.md).
-
-## Prerequisites
-
-In addition to the common prerequisites:
-
-1. An **Azure AI Foundry project** with a chat model deployed (e.g., `gpt-5.2`, `gpt-4o-mini`)
-2. The **Azure AI Developer** role assigned on the Foundry resource (includes the `agents/write` data action required by `UseFoundryTools`)
-3. An **MCP tool connection** configured in your Foundry project pointing to `https://learn.microsoft.com/api/mcp`
-
-## Environment Variables
-
-In addition to the common environment variables in the root README:
-
-```powershell
-# Your Azure AI Foundry project endpoint (required by UseFoundryTools)
-$env:AZURE_AI_PROJECT_ENDPOINT="https://your-resource.services.ai.azure.com/api/projects/your-project"
-
-# Chat model deployment name (defaults to gpt-4o-mini if not set)
-$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
-
-# The MCP tool connection name (just the name, not the full ARM resource ID)
-$env:MCP_TOOL_CONNECTION_ID="SampleMCPTool"
-```
-
-## How It Works
-
-1. An `AzureOpenAIClient` is created with `DefaultAzureCredential` and used to get a chat client
-2. The chat client is wrapped with `UseFoundryTools` which registers two Foundry tool types:
- - **MCP connection**: Connects to an external MCP server (Microsoft Learn) via the project connection name, providing documentation fetch and search capabilities
- - **Code interpreter**: Allows the agent to execute code snippets when needed
-3. `UseFoundryTools` resolves the connection using `AZURE_AI_PROJECT_ENDPOINT` internally
-4. A `ChatClientAgent` is created with instructions guiding it to use the MCP tools for documentation queries
-5. The agent is hosted using `RunAIAgentAsync` which exposes the OpenAI Responses-compatible API endpoint
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/agent.yaml b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/agent.yaml
deleted file mode 100644
index 5d2b1f8d8d..0000000000
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/agent.yaml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: AgentWithTools
-displayName: "Agent with Tools"
-description: >
- An AI agent that uses Foundry tools (MCP and code interpreter) with Azure OpenAI.
- The agent can fetch Microsoft Learn documentation and run code when needed.
-metadata:
- authors:
- - Microsoft Agent Framework Team
- tags:
- - Azure AI AgentServer
- - Microsoft Agent Framework
- - Tools
- - MCP
- - Code Interpreter
-template:
- kind: hosted
- name: AgentWithTools
- protocols:
- - protocol: responses
- version: v1
- environment_variables:
- - name: AZURE_OPENAI_ENDPOINT
- value: ${AZURE_OPENAI_ENDPOINT}
- - name: AZURE_OPENAI_DEPLOYMENT_NAME
- value: gpt-4o-mini
- - name: MCP_TOOL_CONNECTION_ID
- value: ${MCP_TOOL_CONNECTION_ID}
-resources:
- - name: "gpt-4o-mini"
- kind: model
- id: gpt-4o-mini
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/run-requests.http b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/run-requests.http
deleted file mode 100644
index 22a37ff54e..0000000000
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/run-requests.http
+++ /dev/null
@@ -1,30 +0,0 @@
-@host = http://localhost:8088
-@endpoint = {{host}}/responses
-
-### Health Check
-GET {{host}}/readiness
-
-### Simple string input
-POST {{endpoint}}
-Content-Type: application/json
-{
- "input": "Please use the microsoft_docs_fetch tool to fetch and summarize the Microsoft Learn article at https://learn.microsoft.com/azure/ai-services/openai/overview"
-}
-
-### Explicit input
-POST {{endpoint}}
-Content-Type: application/json
-{
- "input": [
- {
- "type": "message",
- "role": "user",
- "content": [
- {
- "type": "input_text",
- "text": "Please use the microsoft_docs_fetch tool to fetch and summarize the Microsoft Learn article at https://learn.microsoft.com/azure/ai-services/openai/overview"
- }
- ]
- }
- ]
-}
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj
index 3b3af40664..7789abd315 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj
@@ -35,10 +35,10 @@
-
+
-
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/FoundryMultiAgent.csproj b/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/FoundryMultiAgent.csproj
index b2fb41ac5e..e8c7a434b0 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/FoundryMultiAgent.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/FoundryMultiAgent.csproj
@@ -1,4 +1,4 @@
-
+
Exe
net10.0
@@ -33,12 +33,12 @@
-
-
+
+
-
-
-
+
+
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/Program.cs
index 6947c85e3f..8d21eef20a 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/Program.cs
+++ b/dotnet/samples/05-end-to-end/HostedAgents/FoundryMultiAgent/Program.cs
@@ -41,7 +41,7 @@ try
.Build();
Console.WriteLine("Starting Writer-Reviewer Workflow Agent Server on http://localhost:8088");
- await workflow.AsAgent().RunAIAgentAsync();
+ await workflow.AsAIAgent().RunAIAgentAsync();
}
finally
{
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/FoundrySingleAgent/FoundrySingleAgent.csproj b/dotnet/samples/05-end-to-end/HostedAgents/FoundrySingleAgent/FoundrySingleAgent.csproj
index 756f3d30ee..70df458d90 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/FoundrySingleAgent/FoundrySingleAgent.csproj
+++ b/dotnet/samples/05-end-to-end/HostedAgents/FoundrySingleAgent/FoundrySingleAgent.csproj
@@ -33,11 +33,11 @@
-
-
+
+
-
-
+
+
diff --git a/dotnet/samples/05-end-to-end/HostedAgents/README.md b/dotnet/samples/05-end-to-end/HostedAgents/README.md
index a36a9bddd1..919aa4b580 100644
--- a/dotnet/samples/05-end-to-end/HostedAgents/README.md
+++ b/dotnet/samples/05-end-to-end/HostedAgents/README.md
@@ -6,7 +6,6 @@ These samples demonstrate how to build and host AI agents using the [Azure AI Ag
| Sample | Description |
|--------|-------------|
-| [`AgentWithTools`](./AgentWithTools/) | Foundry tools (MCP + code interpreter) via `UseFoundryTools` |
| [`AgentWithLocalTools`](./AgentWithLocalTools/) | Local C# function tool execution (Seattle hotel search) |
| [`AgentThreadAndHITL`](./AgentThreadAndHITL/) | Human-in-the-loop with `ApprovalRequiredAIFunction` and thread persistence |
| [`AgentWithHostedMCP`](./AgentWithHostedMCP/) | Hosted MCP server tool (Microsoft Learn search) |
@@ -40,19 +39,18 @@ Most samples require one or more of these environment variables:
|----------|---------|-------------|
| `AZURE_OPENAI_ENDPOINT` | Most samples | Your Azure OpenAI resource endpoint URL |
| `AZURE_OPENAI_DEPLOYMENT_NAME` | Most samples | Chat model deployment name (defaults to `gpt-4o-mini`) |
-| `AZURE_AI_PROJECT_ENDPOINT` | AgentWithTools, AgentWithLocalTools, FoundryMultiAgent, FoundrySingleAgent | Azure AI Foundry project endpoint |
-| `MCP_TOOL_CONNECTION_ID` | AgentWithTools | Foundry MCP tool connection name |
+| `AZURE_AI_PROJECT_ENDPOINT` | AgentWithLocalTools, FoundryMultiAgent, FoundrySingleAgent | Azure AI Foundry project endpoint |
| `MODEL_DEPLOYMENT_NAME` | AgentWithLocalTools, FoundryMultiAgent, FoundrySingleAgent | Chat model deployment name (defaults to `gpt-4o-mini`) |
See each sample's README for the specific variables required.
## Azure AI Foundry Setup (for samples that use Foundry)
-Some samples (`AgentWithTools`, `AgentWithLocalTools`) connect to an Azure AI Foundry project. If you're using these samples, you'll need additional setup.
+Some samples (`AgentWithLocalTools`, `FoundrySingleAgent`, `FoundryMultiAgent`) connect to an Azure AI Foundry project. If you're using these samples, you'll need additional setup.
### Azure AI Developer Role
-The `UseFoundryTools` extension requires the **Azure AI Developer** role on the Cognitive Services resource. Even if you created the project, you may not have this role by default.
+Some Foundry operations require the **Azure AI Developer** role on the Cognitive Services resource. Even if you created the project, you may not have this role by default.
```powershell
az role assignment create `
@@ -65,23 +63,6 @@ az role assignment create `
For more details on permissions, see [Azure AI Foundry Permissions](https://aka.ms/FoundryPermissions).
-### Creating an MCP Tool Connection
-
-The `AgentWithTools` sample requires an MCP tool connection configured in your Foundry project:
-
-1. Go to the [Azure AI Foundry portal](https://ai.azure.com)
-2. Navigate to your project
-3. Go to **Connected resources** → **+ New connection** → **Model Context Protocol tool**
-4. Fill in:
- - **Name**: `SampleMCPTool` (or any name you prefer)
- - **Remote MCP Server endpoint**: `https://learn.microsoft.com/api/mcp`
- - **Authentication**: `Unauthenticated`
-5. Click **Connect**
-
-The connection **name** (e.g., `SampleMCPTool`) is used as the `MCP_TOOL_CONNECTION_ID` environment variable.
-
-> **Important**: Use only the connection **name**, not the full ARM resource ID.
-
## Running a Sample
Each sample runs as a standalone hosted agent on `http://localhost:8088/`:
@@ -110,14 +91,6 @@ Each sample includes a `Dockerfile` and `agent.yaml` for deployment. To deploy y
Assign the **Azure AI Developer** role to your user. See [Azure AI Developer Role](#azure-ai-developer-role) above.
-### `Project connection ... was not found`
-
-Make sure `MCP_TOOL_CONNECTION_ID` contains only the connection **name** (e.g., `SampleMCPTool`), not the full ARM resource ID path.
-
-### `AZURE_AI_PROJECT_ENDPOINT must be set`
-
-The `UseFoundryTools` extension requires `AZURE_AI_PROJECT_ENDPOINT`. Set it to your Foundry project endpoint (e.g., `https://your-resource.services.ai.azure.com/api/projects/your-project`).
-
### Multi-framework error when running `dotnet run`
If you see "Your project targets multiple frameworks", specify the framework:
diff --git a/dotnet/src/Microsoft.Agents.AI.Abstractions/AIContextProvider.cs b/dotnet/src/Microsoft.Agents.AI.Abstractions/AIContextProvider.cs
index 9c1286c9b9..641825d1dc 100644
--- a/dotnet/src/Microsoft.Agents.AI.Abstractions/AIContextProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Abstractions/AIContextProvider.cs
@@ -2,10 +2,12 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
+using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
@@ -147,6 +149,7 @@ public abstract class AIContextProvider
// Create a filtered context for ProvideAIContextAsync, filtering input messages
// to exclude non-external messages (e.g. chat history, other AI context provider messages).
+#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var filteredContext = new InvokingContext(
context.Agent,
context.Session,
@@ -156,6 +159,7 @@ public abstract class AIContextProvider
Messages = inputContext.Messages is not null ? this.ProvideInputMessageFilter(inputContext.Messages) : null,
Tools = inputContext.Tools
});
+#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var provided = await this.ProvideAIContextAsync(filteredContext, cancellationToken).ConfigureAwait(false);
@@ -294,7 +298,9 @@ public abstract class AIContextProvider
return default;
}
+#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var subContext = new InvokedContext(context.Agent, context.Session, this.StoreInputRequestMessageFilter(context.RequestMessages), this.StoreInputResponseMessageFilter(context.ResponseMessages!));
+#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
return this.StoreAIContextAsync(subContext, cancellationToken);
}
@@ -372,6 +378,7 @@ public abstract class AIContextProvider
/// The session associated with the agent invocation.
/// The AI context to be used by the agent for this invocation.
/// or is .
+ [Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokingContext(
AIAgent agent,
AgentSession? session,
@@ -431,6 +438,7 @@ public abstract class AIContextProvider
/// that were used by the agent for this invocation.
/// The response messages generated during this invocation.
/// , , or is .
+ [Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokedContext(
AIAgent agent,
AgentSession? session,
diff --git a/dotnet/src/Microsoft.Agents.AI.Abstractions/ChatHistoryProvider.cs b/dotnet/src/Microsoft.Agents.AI.Abstractions/ChatHistoryProvider.cs
index f4f198df97..a2aa8e1ed5 100644
--- a/dotnet/src/Microsoft.Agents.AI.Abstractions/ChatHistoryProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Abstractions/ChatHistoryProvider.cs
@@ -2,10 +2,12 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
+using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
@@ -250,7 +252,9 @@ public abstract class ChatHistoryProvider
return default;
}
+#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var subContext = new InvokedContext(context.Agent, context.Session, this._storeInputRequestMessageFilter(context.RequestMessages), this._storeInputResponseMessageFilter(context.ResponseMessages!));
+#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
return this.StoreChatHistoryAsync(subContext, cancellationToken);
}
@@ -340,6 +344,7 @@ public abstract class ChatHistoryProvider
/// The session associated with the agent invocation.
/// The messages to be used by the agent for this invocation.
/// is .
+ [Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokingContext(
AIAgent agent,
AgentSession? session,
@@ -399,6 +404,7 @@ public abstract class ChatHistoryProvider
/// that were used by the agent for this invocation.
/// The response messages generated during this invocation.
/// , , or is .
+ [Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokedContext(
AIAgent agent,
AgentSession? session,
diff --git a/dotnet/src/Microsoft.Agents.AI.Abstractions/MessageAIContextProvider.cs b/dotnet/src/Microsoft.Agents.AI.Abstractions/MessageAIContextProvider.cs
index c5f367443c..041e621341 100644
--- a/dotnet/src/Microsoft.Agents.AI.Abstractions/MessageAIContextProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Abstractions/MessageAIContextProvider.cs
@@ -2,10 +2,12 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
+using Microsoft.Shared.DiagnosticIds;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
@@ -49,12 +51,14 @@ public abstract class MessageAIContextProvider : AIContextProvider
{
// Call ProvideMessagesAsync directly to return only additional messages.
// The base AIContextProvider.InvokingCoreAsync handles merging with the original input and stamping.
+#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
return new AIContext
{
Messages = await this.ProvideMessagesAsync(
new InvokingContext(context.Agent, context.Session, context.AIContext.Messages ?? []),
cancellationToken).ConfigureAwait(false)
};
+#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
}
///
@@ -109,10 +113,12 @@ public abstract class MessageAIContextProvider : AIContextProvider
// Create a filtered context for ProvideMessagesAsync, filtering input messages
// to exclude non-external messages (e.g. chat history, other AI context provider messages).
+#pragma warning disable MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var filteredContext = new InvokingContext(
context.Agent,
context.Session,
this.ProvideInputMessageFilter(inputMessages));
+#pragma warning restore MAAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var providedMessages = await this.ProvideMessagesAsync(filteredContext, cancellationToken).ConfigureAwait(false);
@@ -163,6 +169,7 @@ public abstract class MessageAIContextProvider : AIContextProvider
/// The session associated with the agent invocation.
/// The messages to be used by the agent for this invocation.
/// or is .
+ [Experimental(DiagnosticIds.Experiments.AgentsAIExperiments)]
public InvokingContext(
AIAgent agent,
AgentSession? session,
diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/Microsoft.Agents.AI.AzureAI.Persistent.csproj b/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/Microsoft.Agents.AI.AzureAI.Persistent.csproj
index bb02f3065a..8e14047919 100644
--- a/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/Microsoft.Agents.AI.AzureAI.Persistent.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/Microsoft.Agents.AI.AzureAI.Persistent.csproj
@@ -20,8 +20,7 @@
Microsoft Agent Framework AzureAI Persistent Agents
Provides Microsoft Agent Framework support for Azure AI Persistent Agents.
-
- false
+
diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/README.md b/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/README.md
index a01debc5ca..0513ad5d99 100644
--- a/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/README.md
+++ b/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/README.md
@@ -1,19 +1,3 @@
# Microsoft.Agents.AI.AzureAI.Persistent
Provides integration between the Microsoft Agent Framework and Azure AI Agents Persistent (`Azure.AI.Agents.Persistent`).
-
-## ⚠️ Known Compatibility Limitation
-
-The underlying `Azure.AI.Agents.Persistent` package (currently 1.2.0-beta.9) targets `Microsoft.Extensions.AI.Abstractions` 10.1.x and references types that were renamed in 10.4.0 (e.g., `McpServerToolApprovalResponseContent` → `ToolApprovalResponseContent`). This causes `TypeLoadException` at runtime when used with ME.AI 10.4.0+.
-
-**Compatible versions:**
-
-| Package | Compatible Version |
-|---|---|
-| `Azure.AI.Agents.Persistent` | 1.2.0-beta.9 (targets ME.AI 10.1.x) |
-| `Microsoft.Extensions.AI.Abstractions` | ≤ 10.3.0 |
-| `OpenAI` | ≤ 2.8.0 |
-
-**Resolution:** An updated version of `Azure.AI.Agents.Persistent` targeting ME.AI 10.4.0+ is expected in 1.2.0-beta.10. The upstream fix is tracked in [Azure/azure-sdk-for-net#56929](https://github.com/Azure/azure-sdk-for-net/pull/56929).
-
-**Tracking issue:** [microsoft/agent-framework#4769](https://github.com/microsoft/agent-framework/issues/4769)
diff --git a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunStreamingTests.cs b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunStreamingTests.cs
index b4a581d81e..487dcd6878 100644
--- a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunStreamingTests.cs
+++ b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunStreamingTests.cs
@@ -4,10 +4,7 @@ using AgentConformance.IntegrationTests;
namespace AzureAIAgentsPersistent.IntegrationTests;
-// Disabled: Azure.AI.Agents.Persistent 1.2.0-beta.9 references McpServerToolApprovalResponseContent
-// which was removed in ME.AI 10.4.0. Re-enable once Persistent targets ME.AI 10.4.0+ (expected in 1.2.0-beta.10).
-// Tracking: https://github.com/microsoft/agent-framework/issues/4769
-[Trait("Category", "IntegrationDisabled")]
+[Trait("Category", "Integration")]
public class AzureAIAgentsChatClientAgentRunStreamingTests() : ChatClientAgentRunStreamingTests(() => new())
{
}
diff --git a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunTests.cs b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunTests.cs
index 8529dac6b4..79a7c24c69 100644
--- a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunTests.cs
+++ b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsChatClientAgentRunTests.cs
@@ -4,10 +4,7 @@ using AgentConformance.IntegrationTests;
namespace AzureAIAgentsPersistent.IntegrationTests;
-// Disabled: Azure.AI.Agents.Persistent 1.2.0-beta.9 references McpServerToolApprovalResponseContent
-// which was removed in ME.AI 10.4.0. Re-enable once Persistent targets ME.AI 10.4.0+ (expected in 1.2.0-beta.10).
-// Tracking: https://github.com/microsoft/agent-framework/issues/4769
-[Trait("Category", "IntegrationDisabled")]
+[Trait("Category", "Integration")]
public class AzureAIAgentsChatClientAgentRunTests() : ChatClientAgentRunTests(() => new())
{
}
diff --git a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentCreateTests.cs b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentCreateTests.cs
index de9a41e1a0..971bf57cbc 100644
--- a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentCreateTests.cs
+++ b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentCreateTests.cs
@@ -14,10 +14,7 @@ using Shared.IntegrationTests;
namespace AzureAIAgentsPersistent.IntegrationTests;
-// Disabled: Azure.AI.Agents.Persistent 1.2.0-beta.9 references McpServerToolApprovalResponseContent
-// which was removed in ME.AI 10.4.0. Re-enable once Persistent targets ME.AI 10.4.0+ (expected in 1.2.0-beta.10).
-// Tracking: https://github.com/microsoft/agent-framework/issues/4769
-[Trait("Category", "IntegrationDisabled")]
+[Trait("Category", "Integration")]
public class AzureAIAgentsPersistentCreateTests
{
private const string SkipCodeInterpreterReason = "Azure AI Code Interpreter intermittently fails to execute uploaded files in CI";
diff --git a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunStreamingTests.cs b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunStreamingTests.cs
index 87f1cfbb70..1ba0ec991e 100644
--- a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunStreamingTests.cs
+++ b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunStreamingTests.cs
@@ -4,10 +4,7 @@ using AgentConformance.IntegrationTests;
namespace AzureAIAgentsPersistent.IntegrationTests;
-// Disabled: Azure.AI.Agents.Persistent 1.2.0-beta.9 references McpServerToolApprovalResponseContent
-// which was removed in ME.AI 10.4.0. Re-enable once Persistent targets ME.AI 10.4.0+ (expected in 1.2.0-beta.10).
-// Tracking: https://github.com/microsoft/agent-framework/issues/4769
-[Trait("Category", "IntegrationDisabled")]
+[Trait("Category", "Integration")]
public class AzureAIAgentsPersistentRunStreamingTests() : RunStreamingTests(() => new())
{
}
diff --git a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunTests.cs b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunTests.cs
index fd4b92e4b9..446b27b817 100644
--- a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunTests.cs
+++ b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentRunTests.cs
@@ -4,10 +4,7 @@ using AgentConformance.IntegrationTests;
namespace AzureAIAgentsPersistent.IntegrationTests;
-// Disabled: Azure.AI.Agents.Persistent 1.2.0-beta.9 references McpServerToolApprovalResponseContent
-// which was removed in ME.AI 10.4.0. Re-enable once Persistent targets ME.AI 10.4.0+ (expected in 1.2.0-beta.10).
-// Tracking: https://github.com/microsoft/agent-framework/issues/4769
-[Trait("Category", "IntegrationDisabled")]
+[Trait("Category", "Integration")]
public class AzureAIAgentsPersistentRunTests() : RunTests(() => new())
{
}
diff --git a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentStructuredOutputRunTests.cs b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentStructuredOutputRunTests.cs
index 34663c29e4..6ec4620ce3 100644
--- a/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentStructuredOutputRunTests.cs
+++ b/dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentStructuredOutputRunTests.cs
@@ -5,10 +5,7 @@ using AgentConformance.IntegrationTests;
namespace AzureAIAgentsPersistent.IntegrationTests;
-// Disabled: Azure.AI.Agents.Persistent 1.2.0-beta.9 references McpServerToolApprovalResponseContent
-// which was removed in ME.AI 10.4.0. Re-enable once Persistent targets ME.AI 10.4.0+ (expected in 1.2.0-beta.10).
-// Tracking: https://github.com/microsoft/agent-framework/issues/4769
-[Trait("Category", "IntegrationDisabled")]
+[Trait("Category", "Integration")]
public class AzureAIAgentsPersistentStructuredOutputRunTests() : StructuredOutputRunTests(() => new())
{
private const string SkipReason = "Fails intermittently on the build agent/CI";
diff --git a/python/packages/core/agent_framework/_tools.py b/python/packages/core/agent_framework/_tools.py
index cf7384588f..f7bc3f0e15 100644
--- a/python/packages/core/agent_framework/_tools.py
+++ b/python/packages/core/agent_framework/_tools.py
@@ -466,9 +466,15 @@ class FunctionTool(SerializationMixin):
if func is None:
return create_model(f"{self.name}_input")
sig = inspect.signature(func)
+ try:
+ type_hints = typing.get_type_hints(func, include_extras=True)
+ except Exception:
+ type_hints = {}
fields: dict[str, Any] = {
pname: (
- _parse_annotation(param.annotation) if param.annotation is not inspect.Parameter.empty else str,
+ _parse_annotation(type_hints.get(pname, param.annotation))
+ if type_hints.get(pname, param.annotation) is not inspect.Parameter.empty
+ else str,
param.default if param.default is not inspect.Parameter.empty else ...,
)
for pname, param in sig.parameters.items()
diff --git a/python/packages/core/tests/core/test_tools_future_annotations.py b/python/packages/core/tests/core/test_tools_future_annotations.py
new file mode 100644
index 0000000000..1c9649dcb9
--- /dev/null
+++ b/python/packages/core/tests/core/test_tools_future_annotations.py
@@ -0,0 +1,134 @@
+# Copyright (c) Microsoft. All rights reserved.
+
+"""Tests for @tool with PEP 563 (from __future__ import annotations).
+
+When ``from __future__ import annotations`` is active, all annotations
+become strings. _resolve_input_model must resolve them via
+typing.get_type_hints() before passing them to Pydantic's create_model.
+"""
+
+from __future__ import annotations
+
+from pydantic import BaseModel
+
+from agent_framework import tool
+from agent_framework._middleware import FunctionInvocationContext
+
+
+class SearchConfig(BaseModel):
+ max_results: int = 10
+
+
+def test_tool_with_context_parameter():
+ """FunctionInvocationContext parameter is excluded from schema under PEP 563."""
+
+ @tool
+ def get_weather(location: str, ctx: FunctionInvocationContext) -> str:
+ """Get the weather for a given location."""
+ return f"Weather in {location}"
+
+ params = get_weather.parameters()
+ assert "ctx" not in params.get("properties", {})
+ assert "location" in params["properties"]
+
+
+def test_tool_with_context_parameter_first():
+ """FunctionInvocationContext as the first parameter is excluded under PEP 563."""
+
+ @tool
+ def get_weather(ctx: FunctionInvocationContext, location: str) -> str:
+ """Get the weather for a given location."""
+ return f"Weather in {location}"
+
+ params = get_weather.parameters()
+ assert "ctx" not in params.get("properties", {})
+ assert "location" in params["properties"]
+
+
+def test_tool_with_optional_param():
+ """Optional[int] is resolved to the actual type, not left as a string."""
+
+ @tool
+ def search(query: str, limit: int | None = None) -> str:
+ """Search for something."""
+ return query
+
+ params = search.parameters()
+ assert params["properties"]["query"]["type"] == "string"
+ limit_schema = params["properties"]["limit"]
+ limit_types = {t["type"] for t in limit_schema["anyOf"]}
+ assert limit_types == {"integer", "null"}
+
+
+def test_tool_with_optional_param_and_context():
+ """Optional param + FunctionInvocationContext both work under PEP 563."""
+
+ @tool
+ def search(query: str, limit: int | None = None, ctx: FunctionInvocationContext | None = None) -> str:
+ """Search for something."""
+ return query
+
+ params = search.parameters()
+ assert params["properties"]["query"]["type"] == "string"
+ limit_schema = params["properties"]["limit"]
+ limit_types = {t["type"] for t in limit_schema["anyOf"]}
+ assert limit_types == {"integer", "null"}
+ assert "ctx" not in params.get("properties", {})
+
+
+def test_tool_with_optional_custom_type():
+ """Optional[CustomType] is resolved under PEP 563 (original bug pattern)."""
+
+ @tool
+ def search(query: str, config: SearchConfig | None = None) -> str:
+ """Search for something."""
+ return query
+
+ params = search.parameters()
+ assert params["properties"]["query"]["type"] == "string"
+ config_schema = params["properties"]["config"]
+ config_types = [t.get("type") for t in config_schema["anyOf"]]
+ assert "null" in config_types
+
+
+def test_tool_with_unresolvable_forward_ref():
+ """Fallback to raw annotations when get_type_hints() fails."""
+ import types
+
+ # Build a function in an isolated namespace so get_type_hints() cannot resolve
+ # the forward reference, exercising the except-branch fallback.
+ ns: dict = {}
+ exec(
+ "def greet(name: str = 'world') -> str:\n '''Greet someone.'''\n return f'Hello {name}'\n",
+ ns,
+ )
+ func = ns["greet"]
+ # Place the function in a throwaway module so get_type_hints() will fail on
+ # any non-builtin forward ref while still having a valid __module__.
+ mod = types.ModuleType("_phantom")
+ func.__module__ = mod.__name__
+
+ t = tool(func)
+ params = t.parameters()
+ assert params["properties"]["name"]["type"] == "string"
+
+
+async def test_tool_invoke_with_context():
+ """Full invocation with FunctionInvocationContext under PEP 563."""
+
+ @tool
+ def get_weather(location: str, ctx: FunctionInvocationContext) -> str:
+ """Get the weather for a given location."""
+ user = ctx.kwargs.get("user", "anon")
+ return f"Weather in {location} for {user}"
+
+ params = get_weather.parameters()
+ assert "ctx" not in params.get("properties", {})
+
+ context = FunctionInvocationContext(
+ function=get_weather,
+ arguments=get_weather.input_model(location="Seattle"),
+ kwargs={"user": "test_user"},
+ )
+ result = await get_weather.invoke(context=context)
+ assert result[0].text == "Weather in Seattle for test_user"