Skip to content

.NET: feat: Implement return-to-previous routing in handoff workflow#4356

Open
lokitoth wants to merge 1 commit intomainfrom
dev/dotnet_workflow/Enable-HandoffHILReturnToPrevious
Open

.NET: feat: Implement return-to-previous routing in handoff workflow#4356
lokitoth wants to merge 1 commit intomainfrom
dev/dotnet_workflow/Enable-HandoffHILReturnToPrevious

Conversation

@lokitoth
Copy link
Member

Motivation and Context

It is often desirable to return control to the user in a handoff orchestration session without losing the context of which Agent is active (and returning to the original starting agent).

Description

  • Implement return-to-previous routing in handoff workflow
  • Also obsoletes HandoffsWorkflowBuilder => HandoffWorkflowBuilder (no "s")

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

- Also obsoletes HandoffsWorkflowBuilder => HandoffWorkflowBuilder (no "s")
Copilot AI review requested due to automatic review settings February 27, 2026 18:58
@markwallace-microsoft markwallace-microsoft added .NET workflows Related to Workflows in agent-framework labels Feb 27, 2026
@github-actions github-actions bot changed the title feat: Implement return-to-previous routing in handoff workflow .NET: feat: Implement return-to-previous routing in handoff workflow Feb 27, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements return-to-previous routing in handoff workflows, allowing subsequent user turns to route directly back to the specialist agent that handled the previous turn, rather than always routing through the initial coordinator agent. The PR also deprecates HandoffsWorkflowBuilder in favor of HandoffWorkflowBuilder (without the 's').

Changes:

  • Added EnableReturnToPrevious() method to configure return-to-previous routing behavior
  • Introduced HandoffsCurrentAgentTracker to track the active agent across turns
  • Modified HandoffState to include CurrentAgentId for routing decisions
  • Deprecated HandoffsWorkflowBuilder and introduced HandoffWorkflowBuilder as the preferred name

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
HandoffsWorkflowBuilder.cs Adds class hierarchy with obsolete HandoffsWorkflowBuilder and new HandoffWorkflowBuilder; implements EnableReturnToPrevious() method and dynamic routing logic
HandoffsCurrentAgentTracker.cs New simple tracker class to maintain current agent ID across workflow turns
HandoffState.cs Adds optional CurrentAgentId parameter to track active agent
HandoffsStartExecutor.cs Updated to accept tracker and pass current agent ID to HandoffState
HandoffsEndExecutor.cs Updated to accept tracker and update current agent ID at workflow completion
HandoffAgentExecutor.cs Determines current agent ID based on handoff target and stores mapping
AgentWorkflowBuilderTests.cs Comprehensive tests covering default behavior, enabled return-to-previous, and edge cases
Comments suppressed due to low confidence (1)

dotnet/src/Microsoft.Agents.AI.Workflows/HandoffsWorkflowBuilder.cs:39

  • The constructor parameter name in the XML documentation incorrectly refers to HandoffsWorkflowBuilder (with 's'), but this is now in the base class HandoffWorkflowBuilderCore. The documentation should be updated to refer to the correct class name or remain generic.
    /// <summary>
    /// Initializes a new instance of the <see cref="HandoffsWorkflowBuilder"/> class with no handoff relationships.
    /// </summary>
    /// <param name="initialAgent">The first agent to be invoked (prior to any handoff).</param>
    internal HandoffsWorkflowBuilder(AIAgent initialAgent)

Comment on lines +198 to +200
HandoffsCurrentAgentTracker? tracker = this._returnToPrevious ? new() : null;
HandoffsStartExecutor start = new(tracker);
HandoffsEndExecutor end = new(tracker);
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HandoffsCurrentAgentTracker is created once per workflow and will be shared if the same workflow instance is reused across multiple sessions. This means the last active agent from one session could become the starting agent for a different session. This is likely fine for the common use case (one workflow instance per conversation session), but could cause unexpected behavior if workflows are reused. Consider documenting that workflows built with EnableReturnToPrevious should not be reused across different conversation sessions, or making the tracker session-scoped.

Copilot uses AI. Check for mistakes.
namespace Microsoft.Agents.AI.Workflows;

/// <inheritdoc/>
[Obsolete("Perfer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed if a future release before GA.")]
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "Perfer" should be "Prefer" in the obsolescence message.

Suggested change
[Obsolete("Perfer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed if a future release before GA.")]
[Obsolete("Prefer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed in a future release before GA.")]

Copilot uses AI. Check for mistakes.
namespace Microsoft.Agents.AI.Workflows;

/// <inheritdoc/>
[Obsolete("Perfer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed if a future release before GA.")]
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammatical error: "This will be removed if a future release" should be "This will be removed in a future release".

Suggested change
[Obsolete("Perfer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed if a future release before GA.")]
[Obsolete("Prefer HandoffWorkflowBuilder (no 's') instead, which has the same API but the preferred name. This will be removed in a future release before GA.")]

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +93
public HandoffsWorkflowBuilder WithHandoffInstructions(string? instructions)
{
this.HandoffInstructions = instructions ?? DefaultHandoffInstructions;
return this;
}

/// <summary>
/// Sets the behavior for filtering <see cref="FunctionCallContent"/> and <see cref="ChatRole.Tool"/> contents from
/// <see cref="ChatMessage"/>s flowing through the handoff workflow. Defaults to <see cref="HandoffToolCallFilteringBehavior.HandoffOnly"/>.
/// </summary>
/// <param name="behavior">The filtering behavior to apply.</param>
public HandoffsWorkflowBuilder WithToolCallFilteringBehavior(HandoffToolCallFilteringBehavior behavior)
{
this._toolCallFilteringBehavior = behavior;
return this;
}

/// <summary>
/// Configures the workflow so that subsequent user turns route directly back to the specialist agent
/// that handled the previous turn, rather than always routing through the initial (coordinator) agent.
/// </summary>
/// <returns>The updated <see cref="HandoffsWorkflowBuilder"/> instance.</returns>
public HandoffsWorkflowBuilder EnableReturnToPrevious()
{
this._returnToPrevious = true;
return this;
}
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return types of methods in HandoffWorkflowBuilderCore should be updated to support both derived classes properly. Currently, all methods return HandoffsWorkflowBuilder (the obsolete class with 's'), which means when using the new HandoffWorkflowBuilder (without 's'), method chaining will return the obsolete type. Consider using protected methods that return this and having both derived classes provide public methods with covariant return types, or use a generic type parameter to achieve proper type polymorphism across the inheritance hierarchy.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET workflows Related to Workflows in agent-framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants