From 0681e046eac1044eb71334ba48320fbcf7f8f868 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 00:32:36 +0000 Subject: [PATCH] fix: reset autonomous turn counter at start of each new HandoffState turn --- .../HandoffWorkflowBuilder.cs | 3 ++- .../Specialized/HandoffAgentExecutor.cs | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs b/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs index 584ad928df..794cbd0099 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs @@ -160,7 +160,8 @@ public class HandoffWorkflowBuilderCore where TBuilder : HandoffWorkfl /// If , a default prompt is used. /// /// - /// The maximum number of autonomous continuation turns per agent per user message. + /// The maximum number of autonomous continuation turns per agent per incoming turn. + /// The counter resets at the beginning of each new turn (each incoming ). /// If , the default limit is used. /// /// The updated builder instance. diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/HandoffAgentExecutor.cs b/dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/HandoffAgentExecutor.cs index e7e8468806..4370e54b41 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/HandoffAgentExecutor.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/HandoffAgentExecutor.cs @@ -53,7 +53,8 @@ internal sealed class HandoffAgentExecutorOptions public string AutonomousModePrompt { get; set; } /// - /// Gets or sets the maximum number of autonomous turns before control is returned to the user. + /// Gets or sets the maximum number of autonomous turns per incoming turn. + /// The counter is reset at the start of every new turn. /// public int AutonomousModeTurnLimit { get; set; } } @@ -342,6 +343,9 @@ internal sealed class HandoffAgentExecutor : } // Reset the counter when ending the turn (handoff requested or turn limit reached). + // This also covers the case where the turn is interrupted by outstanding requests: + // the counter is reset at the start of the next HandleAsync call, but we still + // clean up here on a normal turn exit for clarity. this._autonomousModeTurnCount = 0; HandoffState outgoingState = new(state.IncomingState.TurnToken, result.HandoffTargetId, this._agent.Id); @@ -388,6 +392,11 @@ internal sealed class HandoffAgentExecutor : state = state with { IncomingState = message, ConversationBookmark = newConversationBookmark }; + // Reset the autonomous turn counter at the start of each new HandoffState turn so that + // the limit is applied fresh for every incoming message, regardless of how the previous + // turn ended (e.g. outstanding external requests that prevented an earlier reset). + this._autonomousModeTurnCount = 0; + return await this.ContinueTurnAsync(state, newConversationMessages.ToList(), context, cancellationToken, skipAddIncoming: true) .ConfigureAwait(false); }