Description
Summary
We use Microsoft.Agents.AI (1.0.0) with ChatClientAgent, ChatClientAgentRunOptions, and custom function-calling middleware (agent.AsBuilder().Use(...)). Our product uses dynamic tooling: we only send a bootstrap tool subset to the model first; the model calls activate_tools to add more tools in the same streaming run.
We had to add application-side workarounds that are more about orchestration and timing than raw MEAI types. We’d like clearer first-class guidance or hooks from the Agent Framework so “tools change mid-run” is a supported story.
Note: ChatOptions.Tools snapshot / Clone behavior is also discussed under Microsoft.Extensions.AI (dotnet/extensions #7217, #7218). This issue focuses on MAF-specific integration points.
Environment
Microsoft.Agents.AI / Microsoft.Agents.AI.OpenAI / Microsoft.Agents.AI.Workflows: 1.0.0
Microsoft.Extensions.AI: 10.5.x
Entry: ChatClientAgent + RunStreamingAsync, tools from ChatOptions bound per pass.
- Refreshing ChatOptions.Tools after activate_tools: middleware path was unreliable
Observed: We tried to refresh the effective tool list in function-calling middleware after the activate_tools tool returned. In practice this was not reliable (e.g. ordering, or not every internal path hitting the same middleware completion semantics). The model could still see Function not found for a tool that had just been activated.
Our workaround: We refresh the in-place list bound to the current pass inside the plugin that implements activate_tools (immediately after successful activation), rebuilding the List that backs ChatOptions.Tools for that pass. Comment in code: avoid relying only on MAF middleware order.
Ask:
Document when middleware runs relative to tool execution and the next model request, and whether mutating ChatOptions.Tools from middleware is a supported pattern.
If not, provide a documented hook (e.g. “after tool X returns, recompute tools”) or a callback registered on the agent/session so the framework merges updated tools before the next LLM call.
- ChatClientAgent and FunctionInvokingChatClient / IncludeDetailedErrors
Observed: We need IncludeDetailedErrors = true on FunctionInvokingChatClient so tool failures surface consistently for our UI and logging.
Our workaround: We explicitly wrap the inner IChatClient with FunctionInvokingChatClient, because ChatClientAgent only adds FunctionInvokingChatClient when the inner client does not already contain one (per our reading of behavior). We need predictable error detail regardless of inner wrapping.
Ask: Expose IncludeDetailedErrors (or equivalent) on ChatClientAgentOptions / agent builder so hosts don’t depend on whether the inner pipeline already includes FunctionInvokingChatClient.
- Streaming tool-call deltas
We implemented a small extractor from AgentResponseUpdate to our own stream protocol (call id, incremental JSON args), similar to what we had for a previous stack.
Ask: Point to official recommended patterns/samples for consuming streaming tool call deltas with ChatClientAgent, to reduce duplicated glue code across products.
- Optional: AgentGroupChat / multi-executor paths vs dynamic tools
We documented a potential mismatch: when UseAgentGroupChat-style main session is enabled, worker tool lists may not receive the same ChatOptions/dynamic tool state as the single-agent main path (e.g. ToolsForAgentRound / mutation target). We have not fully aligned those code paths.
Ask: If Group Chat + variable tool sets is a supported combination, please document how to pass the same tool options to all executors.
Code Sample
Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI / Microsoft.Agents.AI.OpenAI / Microsoft.Agents.AI.Workflows: 1.0.0
.NET Version
net10.0
Additional Context
No response
Description
Summary
We use Microsoft.Agents.AI (1.0.0) with ChatClientAgent, ChatClientAgentRunOptions, and custom function-calling middleware (agent.AsBuilder().Use(...)). Our product uses dynamic tooling: we only send a bootstrap tool subset to the model first; the model calls activate_tools to add more tools in the same streaming run.
We had to add application-side workarounds that are more about orchestration and timing than raw MEAI types. We’d like clearer first-class guidance or hooks from the Agent Framework so “tools change mid-run” is a supported story.
Note: ChatOptions.Tools snapshot / Clone behavior is also discussed under Microsoft.Extensions.AI (dotnet/extensions #7217, #7218). This issue focuses on MAF-specific integration points.
Environment
Microsoft.Agents.AI / Microsoft.Agents.AI.OpenAI / Microsoft.Agents.AI.Workflows: 1.0.0
Microsoft.Extensions.AI: 10.5.x
Entry: ChatClientAgent + RunStreamingAsync, tools from ChatOptions bound per pass.
Observed: We tried to refresh the effective tool list in function-calling middleware after the activate_tools tool returned. In practice this was not reliable (e.g. ordering, or not every internal path hitting the same middleware completion semantics). The model could still see Function not found for a tool that had just been activated.
Our workaround: We refresh the in-place list bound to the current pass inside the plugin that implements activate_tools (immediately after successful activation), rebuilding the List that backs ChatOptions.Tools for that pass. Comment in code: avoid relying only on MAF middleware order.
Ask:
Document when middleware runs relative to tool execution and the next model request, and whether mutating ChatOptions.Tools from middleware is a supported pattern.
If not, provide a documented hook (e.g. “after tool X returns, recompute tools”) or a callback registered on the agent/session so the framework merges updated tools before the next LLM call.
Observed: We need IncludeDetailedErrors = true on FunctionInvokingChatClient so tool failures surface consistently for our UI and logging.
Our workaround: We explicitly wrap the inner IChatClient with FunctionInvokingChatClient, because ChatClientAgent only adds FunctionInvokingChatClient when the inner client does not already contain one (per our reading of behavior). We need predictable error detail regardless of inner wrapping.
Ask: Expose IncludeDetailedErrors (or equivalent) on ChatClientAgentOptions / agent builder so hosts don’t depend on whether the inner pipeline already includes FunctionInvokingChatClient.
We implemented a small extractor from AgentResponseUpdate to our own stream protocol (call id, incremental JSON args), similar to what we had for a previous stack.
Ask: Point to official recommended patterns/samples for consuming streaming tool call deltas with ChatClientAgent, to reduce duplicated glue code across products.
We documented a potential mismatch: when UseAgentGroupChat-style main session is enabled, worker tool lists may not receive the same ChatOptions/dynamic tool state as the single-agent main path (e.g. ToolsForAgentRound / mutation target). We have not fully aligned those code paths.
Ask: If Group Chat + variable tool sets is a supported combination, please document how to pass the same tool options to all executors.
Code Sample
Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI / Microsoft.Agents.AI.OpenAI / Microsoft.Agents.AI.Workflows: 1.0.0
.NET Version
net10.0
Additional Context
No response