microsoft / microsoft/agent-framework
.NET: [Bug]: AsAIFunction() fails under Foundry hosting: forwarded ChatHistoryProvider override conflicts with Responses-backed child agent's ConversationId
@rogerbarreto is already working on this.
Since Sep 4, 2026.
- Dominant language
- Python
- Stars
- 13.6k
- Forks
- 2.3k
- Avg merge
- 2d 45m
- Merged PRs (30d)
- 358
Description
### Description
`AIAgent.AsAIFunction()` (agent-as-tool) fails when the *parent* agent runs under Foundry hosting (`AddFoundryResponses` / `MapFoundryResponses`) and the *child* agent is a Responses-backed `ChatClientAgent` created with `AIProjectClient.AsAIAgent(...)`.
Cause, as far as I can tell from the source:
1. The Foundry hosting layer runs the parent agent with an override `ChatHistoryProvider` in `AgentRunOptions.AdditionalProperties` (the Responses protocol's own history store).
2. `AsAIFunction` deliberately forwards the parent run's `AdditionalProperties` to the child run (`AgentExtensions.cs`: `FunctionInvokingChatClient.CurrentContext?.Options?.AdditionalProperties` → `new AgentRunOptions { AdditionalProperties = dict }`).
3. The child is bound to the project's Responses API, so the service returns a conversation id. `ChatClientAgent.ResolveChatHistoryProvider` then sees both a `ConversationId` and an override `ChatHistoryProvider` and throws.
Each rule is fine on its own; the combination makes the documented agent-as-tool pattern (sample `Agent_Step09_AsFunctionTool`) unusable inside a hosted agent. The same code works when the parent is run directly with `agent.RunAsync(...)` from a console app, since nothing injects the override.
Two smaller points that made this hard to diagnose:
- The function-invoking client swallows the exception and returns the tool result `Error: Function failed.` to the model, with nothing logged. I only found the cause by wrapping the function in a `DelegatingAIFunction` that catches and prints the exception.
- Forwarding the parent's `ChatHistoryProvider` to a child is arguably never desired: the child would read and write the parent's conversation history.
**Expected:** `child.AsAIFunction()` works for a Responses-backed child under Foundry hosting, or at least there is a way to opt out of the `AdditionalProperties` propagation.
**Workaround:** replace `AsAIFunction` with a hand-written `AIFunction` that calls `child.RunAsync(task, cancellationToken: ct)` with no session and no run options.
### Code Sample
```csharp
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry.Hosting;
using Microsoft.Extensions.AI;
var endpoint = new Uri(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")!);
var model = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME")!;
var client = new AIProjectClient(endpoint, new DefaultAzureCredential());
AIAgent child = client.AsAIAgent(
model: model,
instructions: "Answer the question briefly.",
name: "child",
description: "Answers one question.");
AIAgent parent = client.AsAIAgent(
model: model,
instructions: "Use the child tool to answer any question.",
name: "parent",
tools: [child.AsAIFunction()]);
var builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(parent);
builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses());
builder.Build().Run();
```
Run with `azd ai agent run`, then `azd ai agent invoke --local 'Ask the child what 2+2 is'`. The parent reports that the tool returned `Error: Function failed.`
### Error Messages / Stack Traces
```text
System.InvalidOperationException: Only ConversationId or ChatHistoryProvider may be used, but not both. A ConversationId indicating server-side chat history management is present (on the ChatClientAgentSession or the ChatOptions), but an override ChatHistoryProvider was provided via AdditionalProperties.
at Microsoft.Agents.AI.ChatClientAgent.ResolveChatHistoryProvider(ChatClientAgentSession session, ChatOptions chatOptions)
at Microsoft.Agents.AI.ChatClientAgent.NotifyProvidersOfNewMessagesAsync(ChatClientAgentSession session, IEnumerable`1 requestMessages, IEnumerable`1 responseMessages, ChatOptions chatOptions, CancellationToken cancellationToken)
at Microsoft.Agents.AI.ChatClientAgent.RunCoreAsync(IEnumerable`1 messages, AgentSession session, AgentRunOptions options, CancellationToken cancellationToken)
at Microsoft.Agents.AI.AIAgent.RunAsync(IEnumerable`1 messages, AgentSession session, AgentRunOptions options, CancellationToken cancellationToken)
at Microsoft.Agents.AI.AIAgentExtensions.<>c__DisplayClass1_0.<g__InvokeAgentAsync|0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.Extensions.AI.AIFunctionFactory.ReflectionAIFunctionDescriptor.<>c__DisplayClass41_1.<b__12>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.Extensions.AI.AIFunctionFactory.ReflectionAIFunction.InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken)
```
(Captured by wrapping the function in a `DelegatingAIFunction`; without that the only visible symptom is the tool result `Error: Function failed.`)
### Package Versions
- Microsoft.Agents.AI.Foundry.Hosting 1.20.0-preview.260831.1
- Microsoft.Agents.AI.Foundry 1.20.0-preview.260831.1
- Microsoft.Agents.AI 1.20.0
- Microsoft.Agents.AI.Abstractions 1.20.0
- Azure.AI.AgentServer.Core 1.0.0-beta.28
- Azure.AI.AgentServer.Responses 1.0.0-beta.8
- Azure.AI.Projects 3.0.0-beta.1
### .NET Version
.NET 10.0.100 SDK, `net10.0` target, Windows 11 (local `azd ai agent run`; not yet verified in the hosted container, but the hosting layer is the same)
### Additional Context
Not the same as #4937: there the agent itself has a `ChatHistoryProvider` configured and the request is stateless. Here the child agent has no provider of its own; the override arrives via `AsAIFunction` forwarding the hosted parent's run options.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.