microsoft / microsoft/agent-framework

.NET: [Bug]: ChatClientAgent.RunStreamingAsync ends with no assistant text on multi-tool turns (reasoning model + stateless Responses API)

Open
#6,268 1 comment 1 reaction 1 assignee View on GitHub

@giles17 is already working on this.

Since Jun 2, 2026.

.NET needs-maintainer-triage
Dominant language
Python
Stars
13.6k
Forks
2.3k
Avg merge
2d 45m
Merged PRs (30d)
358

Description

Description

What happened?
Using ChatClientAgent.RunStreamingAsync with a reasoning deployment (GPT-5 family) over the Azure Foundry Responses API in stateless mode (AsIChatClientWithStoredOutputDisabled, i.e. StoredOutputEnabled=false), a turn that involves MULTIPLE tool calls frequently ends with NO final assistant TextContent.

  • The tools execute fine and return results.
  • The continuation request to /openai/responses returns HTTP 200, but the stream produces no answer text.
  • The last update has FinishReason = ToolCalls, and OutputTokenCount is tiny (~15–125).
  • Single-tool / simple turns work correctly. The problem is specific to turns that fan out into several tool calls.

All tools are ordinary invocable AIFunctions created via AIFunctionFactory.Create (no hosted/server-side tools). The framework defaults for MaximumIterationsPerRequest (40) and MaximumConsecutiveErrorsPerRequest (3) are not reached.

What did you expect to happen?
After the tool calls and tool results, the FunctionInvokingChatClient continuation request should return a final assistant message containing answer text. Instead the loop ends on a tool-call turn with no text.

Steps to reproduce

  1. Create a ChatClientAgent over a reasoning deployment using GetResponsesClient().AsIChatClientWithStoredOutputDisabled(deployment) (store=false; reasoning encrypted content included by default).
  2. Register a few invocable function tools and use an InMemoryChatHistoryProvider.
  3. Stream via RunStreamingAsync and ask a question that drives several tool calls in one turn.
  4. Observe: tools run, then the stream ends with FinishReason=ToolCalls and no assistant TextContent.
Code Sample
[Description("Gets the current weather for a city.")]
  static string GetWeather(string city) => $"{city}: 18°C, cloudy";

  [Description("Looks up the population of a city.")]
  static string GetPopulation(string city) => $"{city}: 1,200,000";

  var chatClient = new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey))
      .GetResponsesClient()
      .AsIChatClientWithStoredOutputDisabled(deploymentName); // store=false + ReasoningEncryptedContent (default)

  var agent = new ChatClientAgent(chatClient, new ChatClientAgentOptions
  {
      ChatOptions = new ChatOptions
      {
          Tools = new AITool[]
          {
              AIFunctionFactory.Create(GetWeather),
              AIFunctionFactory.Create(GetPopulation),
          }
      },
      ChatHistoryProvider = new InMemoryChatHistoryProvider()
  });

  var session = agent.GetNewSession();

  // A prompt that drives multiple tool calls in one turn:
  await foreach (var update in agent.RunStreamingAsync(
      "Compare the weather and population of London and Paris.", session))
  {
      // On the failing turn: update.Text is empty and
      // update.FinishReason == ChatFinishReason.ToolCalls (no final answer text).
      Console.Write(update.Text);
  }
Error Messages / Stack Traces
No exception is surfaced to the caller on the failing turn — the stream simply ends with no TextContent
  (FinishReason=ToolCalls, small OutputTokenCount, continuation request == HTTP 200).

  Intermittently, on the failing turn only, disposing the streaming enumerator throws:

  System.NotSupportedException: Specified method is not supported.
     at Microsoft.Agents.AI.AIAgent.RunStreamingAsync(IEnumerable`1 messages, AgentSession session, AgentRunOptions options, CancellationToken cancellationToken)+System.IAsyncDisposable.DisposeAsync()
Package Versions

Microsoft.Agents.AI: 1.8.0 Microsoft.Agents.AI.OpenAI: 1.8.0 Microsoft.Extensions.AI: 10.5.1 Microsoft.Extensions.AI.OpenAI: 10.5.1 OpenAI: 2.10.0 Azure.AI.OpenAI: 2.9.0-beta.1

.NET Version

.NET 10

Additional Context

Questions:

  1. Under stateless Responses API + reasoning model + multiple tool calls in STREAMING, is there a known case where the continuation returns HTTP 200 with only a reasoning item and no output text, leaving the loop to end on FinishReason=ToolCalls? Is reasoning.encrypted_content expected to round-trip reliably
    through the FunctionInvokingChatClient streaming loop at these versions?
  2. What causes AIAgent.RunStreamingAsync's enumerator DisposeAsync to throw NotSupportedException? Is it a symptom of an aborted/incomplete inner stream?
  3. Is persisting and replaying reasoning items across turns (via a serialized AgentSession) supported under StoredOutputEnabled=false, or should reasoning items be excluded before persistence?

The problem reproduces consistently for tool-heavy prompts.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.