You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
we have agent decorated with skill loading provider context provider - no issue
we wanted to add another augmenting context provider but even if the provider literally returns
newAIContext()
in ProvideAIContextAsync and nothing else, we see skill loading breaking with
Task failed: HTTP 400 (invalid_request_error: )
Parameter: input
Item 'fc_007f6e0e4e84d6ca006a5e107039ec8196aea3835af4b14dce' of type 'function_call' was provided without its required 'reasoning' item: 'rs_007f6e0e4e84d6ca006a5e106fd43881969b6860989376dab2'.
Task failed: HTTP 400 (invalid_request_error: )
Parameter: input
Item 'fc_007f6e0e4e84d6ca006a5e107039ec8196aea3835af4b14dce' of type 'function_call' was provided without its required 'reasoning' item: 'rs_007f6e0e4e84d6ca006a5e106fd43881969b6860989376dab2'.
Your error about 'function_call provided without its required reasoning item' is an OpenAI Responses API constraint for reasoning models (o3, o4-mini, etc.). We wrote unit tests matching your scenario — an empty AIContextProvider returning new AIContext() combined with tool calls that include TextReasoningContent — and reasoning is preserved correctly through the provider pipeline in both PerServiceCall and end-of-run persistence modes. To help reproduce on our side, could you share: (1) which OpenAI model you're using, (2) whether you're using AsIChatClientWithStoredOutputDisabled or the standard AsIChatClient, (3) whether RequirePerServiceCallChatHistoryPersistence is enabled, and (4) the full agent configuration/pipeline setup? The framework code itself does not strip reasoning items when an empty provider is added.
Once you can share the details above, we'll take another look. 🙏
Your error about 'function_call provided without its required reasoning item' is an OpenAI Responses API constraint for reasoning models (o3, o4-mini, etc.). We wrote unit tests matching your scenario — an empty AIContextProvider returning new AIContext() combined with tool calls that include TextReasoningContent — and reasoning is preserved correctly through the provider pipeline in both PerServiceCall and end-of-run persistence modes. To help reproduce on our side, could you share: (1) which OpenAI model you're using, (2) whether you're using AsIChatClientWithStoredOutputDisabled or the standard AsIChatClient, (3) whether RequirePerServiceCallChatHistoryPersistence is enabled, and (4) the full agent configuration/pipeline setup? The framework code itself does not strip reasoning items when an empty provider is added.
Once you can share the details above, we'll take another look. 🙏
it seems the underlying differentiator is whether the agent is invoked with or without session
so I had AI generate a kind of demo console app to demo what we have been seeing
/* * Router Agent Session Demo * ========================= * This console app registers the RouterAgent exactly as the FluxBackend does * (the USE_MAF_AGENTS path) and then demonstrates two scenarios: * * 1. WITHOUT a session → fails with InvalidOperationException because * ExternalMemoryAIContextProvider requires a "sessionId" in run options. * * 2. WITH a session + sessionId → succeeds and prints the OrchestrationEnvelope. * * Prerequisites (user-secrets or environment variables): * flux-backend:azure-openai-endpoint (Azure OpenAI endpoint URL) * flux-backend:azure-openai-deployment-name (model deployment name) */usingFlux.Backend;usingFlux.Backend.AgentInstructions;usingFlux.Backend.Contracts;usingFlux.Backend.Services;usingMicrosoft.Agents.AI;usingMicrosoft.Agents.AI.Hosting;usingMicrosoft.Extensions.AI;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Hosting;usingMicrosoft.Extensions.Logging;usingSystem.Text.Json;// ──────────────────────────────────────────────// 1. Build configuration (user secrets + env)// ──────────────────────────────────────────────varconfig=newConfigurationBuilder().AddJsonFile("appsettings.json",optional:true).AddUserSecrets<Program>().AddEnvironmentVariables().Build();stringendpoint=config["flux-backend:azure-openai-endpoint"]??thrownewInvalidOperationException("flux-backend:azure-openai-endpoint is not set.");stringdeployment=config["flux-backend:azure-openai-deployment-name"]??thrownewInvalidOperationException("flux-backend:azure-openai-deployment-name is not set.");// ──────────────────────────────────────────────// 2. Build the host / DI container// ──────────────────────────────────────────────
#pragma warning disable MAAI001varhost=Host.CreateDefaultBuilder().ConfigureLogging(logging =>{logging.ClearProviders();logging.AddConsole();logging.SetMinimumLevel(LogLevel.Warning);// keep output tidy}).ConfigureServices((_,services)=>{// Chat client (same factory as the backend)services.AddSingleton<IChatClient>(_ =>OpenAIChatClientFactory.Create(endpoint,deployment).AsBuilder().Build());// Empty dummy AI context provider for demo purposesservices.AddSingleton<EmptyDummyAIContextProvider>();// Router agent skills provider (points at the Artefacts output directory)varskillsBasePath=Path.Combine(AppContext.BaseDirectory,"skills");varrouterValidatorSkillsProvider=newAgentSkillsProvider(skillPath:Path.Join(skillsBasePath,"routervalidator"));// Auto-approve all tool calls (same as backend)Func<FunctionCallContent,ValueTask<bool>>autoApprove=
_ =>ValueTask.FromResult(true);// Session store (in-memory, same as backend)services.AddSingleton<AgentSessionStore,InMemoryAgentSessionStore>();// RouterValidator agent ← registered exactly as in Program.cs (USE_MAF_AGENTS)services.AddAIAgent(Consts.RouterValidatorAgentName,(sp,_)=>{varchatClient=sp.GetRequiredService<IChatClient>();varoptions=newChatClientAgentOptions{Name=Consts.RouterValidatorAgentName,AIContextProviders=[sp.GetRequiredService<EmptyDummyAIContextProvider>(),routerValidatorSkillsProvider],ChatOptions=newChatOptions{Seed=123456789,Instructions=Router.RouterAgentInstructions}};returnnewChatClientAgent(chatClient,options).AsBuilder().UseToolApproval(newToolApprovalAgentOptions{AutoApprovalRules=[autoApprove]}).Build();});// Session agent (dummy, used only to hold session state)services.AddAIAgent(Consts.SessionAgent,(sp,_)=>{varchatClient=sp.GetRequiredService<IChatClient>();varoptions=newChatClientAgentOptions{Name=Consts.SessionAgent,ChatOptions=newChatOptions{Seed=123456789,Instructions="you are fake agent and only used internally to store and load sessions",}};returnnewChatClientAgent(chatClient,options).AsBuilder().UseToolApproval(newToolApprovalAgentOptions{AutoApprovalRules=[autoApprove]}).Build();});}).Build();
#pragma warning restore MAAI001// ──────────────────────────────────────────────// 3. Resolve agents// ──────────────────────────────────────────────varsp=host.Services;varrouterAgent=sp.GetRequiredKeyedService<AIAgent>(Consts.RouterValidatorAgentName);varsessionAgent=sp.GetRequiredKeyedService<AIAgent>(Consts.SessionAgent);varsessionStore=sp.GetRequiredService<AgentSessionStore>();conststringdemoPrompt="onboard project Helios with owner [email protected]";// ──────────────────────────────────────────────// 4. DEMO A — without session (expected failure)// ──────────────────────────────────────────────Console.ForegroundColor=ConsoleColor.Yellow;Console.WriteLine("════════════════════════════════════════════════");Console.WriteLine(" DEMO A — Running WITHOUT a session");Console.WriteLine("════════════════════════════════════════════════");Console.ResetColor();Console.WriteLine($"Prompt: {demoPrompt}");Console.WriteLine();try{varsessionId=Guid.NewGuid().ToString();varsession=awaitSessionService.GetOrCreateSessionAsync(sessionStore,sessionAgent,sessionId);// No session, no sessionId in run options → ExternalMemoryAIContextProvider will throwvarresultA=awaitStructuredAgentRunner.RunAsync<OrchestrationEnvelope>(routerAgent,demoPrompt,session:null,sessionId:sessionId,storeContext:true,cancellationToken:CancellationToken.None);Console.ForegroundColor=ConsoleColor.Red;Console.WriteLine("⚠ Expected a failure but got a result — this is unexpected:");Console.ResetColor();Console.WriteLine(JsonSerializer.Serialize(resultA,newJsonSerializerOptions{WriteIndented=true}));}catch(InvalidOperationExceptionex)when(ex.Message.Contains("Session ID is missing")){Console.ForegroundColor=ConsoleColor.Green;Console.WriteLine($"✓ Got the expected failure: {ex.Message}");Console.ResetColor();}catch(Exceptionex){Console.ForegroundColor=ConsoleColor.Red;Console.WriteLine($"✗ Got an unexpected exception: {ex.GetType().Name}: {ex.Message}");Console.ResetColor();}Console.WriteLine();// ──────────────────────────────────────────────// 5. DEMO B — with session (expected success)// ──────────────────────────────────────────────Console.ForegroundColor=ConsoleColor.Cyan;Console.WriteLine("════════════════════════════════════════════════");Console.WriteLine(" DEMO B — Running WITH a session");Console.WriteLine("════════════════════════════════════════════════");Console.ResetColor();Console.WriteLine($"Prompt: {demoPrompt}");Console.WriteLine();try{varsessionId=Guid.NewGuid().ToString();// GetOrCreateSession gives us a proper AgentSessionvarsession=awaitSessionService.GetOrCreateSessionAsync(sessionStore,sessionAgent,sessionId);// Pass the session AND sessionId in run options, exactly as RouterAgentActivity doesvarresultB=awaitStructuredAgentRunner.RunAsync<OrchestrationEnvelope>(routerAgent,demoPrompt,session,sessionId:sessionId,storeContext:true,cancellationToken:CancellationToken.None);Console.ForegroundColor=ConsoleColor.Green;Console.WriteLine("✓ Agent returned a result:");Console.ResetColor();Console.WriteLine(JsonSerializer.Serialize(resultB,newJsonSerializerOptions{WriteIndented=true}));}catch(Exceptionex){Console.ForegroundColor=ConsoleColor.Red;Console.WriteLine($"✗ Unexpected exception: {ex.GetType().Name}: {ex.Message}");if(ex.InnerExceptionis not null)Console.WriteLine($" Inner: {ex.InnerException.Message}");Console.ResetColor();}internalsealedclassEmptyDummyAIContextProvider:AIContextProvider{publicoverrideIReadOnlyList<string>StateKeys=>[];protectedoverrideValueTask<AIContext>ProvideAIContextAsync(InvokingContextcontext,CancellationTokencancellationToken=default){returnValueTask.FromResult(newAIContext());}}
you will see the difference being session null for Demo A and that produces skill load tool call exception as opposed to session being provided for Demo B and that completes as expected
which produces
DEMO A - Running WITHOUT a session
════════════════════════════════════════════════
Prompt: onboard project Helios with owner [email protected]
? Got an unexpected exception: ClientResultException: HTTP 400 (invalid_request_error: )
Parameter: input
Item 'fc_08513de623800d8e006a5f9ef17e7c81939dbab52b49fa67d3' of type 'function_call' was provided without its required 'reasoning' item: 'rs_08513de623800d8e006a5f9ef0ab4c8193a52f5167e57774f7'.
════════════════════════════════════════════════
DEMO B - Running WITH a session
════════════════════════════════════════════════
Prompt: onboard project Helios with owner [email protected]
√ Agent returned a result:
{
"SubPrompt": "onboard project Helios with owner [email protected]",
"WorkItems": [
{
"Domain": "ado",
"Prompt": "create or ensure Azure DevOps project with the name \u0027Helios\u0027 with project administrator \[email protected]\u0027",
"RouteAfterCompletion": "return_to_router"
},
{
"Domain": "teams",
"Prompt": "create or ensure Team with the name \u0027Helios\u0027 with owner of \[email protected]\u0027 and ensure the private \u0027Configuration\u0027 channel exists in the team and ensure \[email protected]\u0027 is a member of the channel and team",
"RouteAfterCompletion": "return_to_router"
},
{
"Domain": "github",
"Prompt": "create github organization team \u0027Helios\u0027",
"RouteAfterCompletion": "return_to_router"
}
],
"Context": [
"Project onboarding requested for project \u0027Helios\u0027 with owner \[email protected]\u0027.",
"After GitHub project-level onboarding is completed, schedule GitHub user onboarding for owner \[email protected]\u0027 to GitHub organization team \u0027Helios\u0027; this requires the target user\u0027s GitHub handle before the GitHub user onboarding work can be emitted."
],
"EngagementQueueItems": [],
"RequiresEngagement": false,
"EngagementType": 0,
"Succeeded": true,
"Error": null,
"ResultSummary": "Routed project onboarding for \u0027Helios\u0027 into Azure DevOps, Teams, and GitHub core work items. GitHub user onboarding for owner \[email protected]\u0027 is deferred until after core project onboarding and requires the owner\u2019s GitHub handle."
}
C:\projects\Flux\src\RouterAgentDemo\bin\Debug\net10.0\RouterAgentDemo.exe (process 56004) exited with code 0 (0x0).
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .
Oisin Haken (@VaclavK), which responses service are you using? E.g. OpenAI directly, or are you using Foundry or some other responses compatible service?
Oisin Haken (@VaclavK), I haven't been able to repro your exact failure, but I believe it's most likely related to the tool auto approval feature, which does multiple sub agent invocations without a session, and this is a bug. I've created a PR to fix.
Some general tips:
If you just want to approve everything (yolo mode), there is a built in approval rule already you can use: ToolApprovalAgent.AllToolsAutoApprovalRule, so you don't need to write your own.
Activity
github-actions commentedon Jul 20, 2026
👋 Hi Oisin Haken (@VaclavK) — thanks for the report!
Your error about 'function_call provided without its required reasoning item' is an OpenAI Responses API constraint for reasoning models (o3, o4-mini, etc.). We wrote unit tests matching your scenario — an empty AIContextProvider returning
new AIContext()combined with tool calls that include TextReasoningContent — and reasoning is preserved correctly through the provider pipeline in both PerServiceCall and end-of-run persistence modes. To help reproduce on our side, could you share: (1) which OpenAI model you're using, (2) whether you're usingAsIChatClientWithStoredOutputDisabledor the standardAsIChatClient, (3) whetherRequirePerServiceCallChatHistoryPersistenceis enabled, and (4) the full agent configuration/pipeline setup? The framework code itself does not strip reasoning items when an empty provider is added.Once you can share the details above, we'll take another look. 🙏
VaclavK commentedon Jul 20, 2026
it seems the underlying differentiator is whether the agent is invoked with or without session
or
completes with session, throws the error without session
we are using gpt-5.5
we use standard AI client set up as follows
the inner client is set up as
VaclavK commentedon Jul 20, 2026
it seems the underlying differentiator is whether the agent is invoked with or without session
or
completes with session, throws the error without session
we are using gpt-5.5
we use standard AI client set up as follows
the inner client is set up as
VaclavK commentedon Jul 21, 2026
so I had AI generate a kind of demo console app to demo what we have been seeing
you will see the difference being session null for Demo A and that produces skill load tool call exception as opposed to session being provided for Demo B and that completes as expected
which produces
westey-m commentedon Jul 23, 2026
Oisin Haken (@VaclavK), which responses service are you using? E.g. OpenAI directly, or are you using Foundry or some other responses compatible service?
VaclavK commentedon Jul 24, 2026
Foundry hosted chatgpt-5.5 model deployment
westey-m commentedon Jul 24, 2026
Oisin Haken (@VaclavK), I haven't been able to repro your exact failure, but I believe it's most likely related to the tool auto approval feature, which does multiple sub agent invocations without a session, and this is a bug. I've created a PR to fix.
Some general tips:
If you just want to approve everything (yolo mode), there is a built in approval rule already you can use:
ToolApprovalAgent.AllToolsAutoApprovalRule, so you don't need to write your own.Also, the SkillsProvider allows you to pass options that can switch off tool approval entirely for loading skills/resources and executing skill scripts, which means you may not need
.UseToolApproval(new ToolApprovalAgentOptions { AutoApprovalRules = [autoApprove] }).See https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderOptions.cs#L44.