Skip to content

.NET: Fix reasoning remnants and handoff bounce-back - #9174

Merged
Vincent Biret (baywet) merged 8 commits into
mainfrom
fix/handoff-reasoning-filter-7384
Oct 14, 2026
Merged

Vincent Biret (baywet) merged 8 commits into
mainfrom
fix/handoff-reasoning-filter-7384

Conversation

@baywet

@baywet Vincent Biret (baywet) commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Motivation & Context

When an assistant response contains both reasoning and a handoff function call, handoff filtering removes the function call and its result but retains a reasoning-only message. The receiving agent then sees that message after the user's request. The final report in #7384 identifies this deterministic filtering defect as a contributor to silent turns when providers return reasoning summaries.

The same issue also confirms a separate same-turn bounce-back defect: when control returns to an agent, its pending handoff result is delivered without a fresh request to act on. With service-managed history this can reduce the entire request delta to one tool result. This PR now addresses both defects.

Description & Review Guide

  • What are the major changes? Drop reasoning-only remnants of filtered tool messages. Track each participant's pending handoff call across checkpoints and, on return without new user input, reissue the latest user request with a fresh message identifier. Add model-free filtering and bounce-back regressions covering local/service-managed history, reasoning, streaming/non-streaming, checkpoint restore, and ordinary tool continuations. Document the behavior. The net472 CI correction also keeps the preexisting stale-waiter test's blocking lock off the thread pool.
  • What is the impact of these changes? Returning agents receive an actionable request while retaining their existing session, ConversationId, and required handoff call/result pairing. New user input is not replayed again; participant-local replays never enter the shared workflow transcript. Filtering still preserves standalone reasoning, unfiltered tools, visible text, and original messages. There are no public API changes, and production background-agent code is unchanged.
  • What do you want reviewers to focus on? Matching reactivation to the participant's own pending handoff result, distinguishing genuine user input from approval responses, and preserving session state and transcript boundaries. The checkpoint controls rebuild the workflow and verify both replay and no-replay paths. This fixes the confirmed handoff payload defects rather than retrying or inventing text for arbitrary empty provider completions.

Local validation, run from dotnet\ without a live model:

Command Result
dotnet build 'src\Microsoft.Agents.AI.Workflows\Microsoft.Agents.AI.Workflows.csproj' --no-restore --tl:off Passed for net10.0, net9.0, net8.0, netstandard2.0, and net472; 0 warnings and 0 errors.
dotnet test --project 'tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj' -f net10.0 --no-restore --filter-query '/*/*/Handoff*/*' Passed: 108 tests, 0 failures, 0 skipped.
dotnet test --project 'tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj' -f net472 -c Release --no-restore --filter-query '/*/*/Handoff*/*' Passed: 108 tests, 0 failures, 0 skipped.
dotnet test --project 'tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj' -f net10.0 --no-build --no-restore Passed: all 826 workflow unit tests, 0 failures, 0 skipped.
dotnet test --project 'tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj' -f net472 -c Release --no-build --no-restore Passed: all 807 workflow unit tests, 0 failures, 0 skipped.
dotnet format 'src\Microsoft.Agents.AI.Workflows\Microsoft.Agents.AI.Workflows.csproj' --no-restore --include 'src\Microsoft.Agents.AI.Workflows\Specialized\HandoffAgentExecutor.cs' 'src\Microsoft.Agents.AI.Workflows\HandoffWorkflowBuilder.cs' --verbosity minimal Passed.
dotnet format 'tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj' --no-restore --include 'tests\Microsoft.Agents.AI.Workflows.UnitTests\HandoffOrchestrationTests.cs' --verbosity minimal Passed.
dotnet test --project 'tests\Microsoft.Agents.AI.UnitTests\Microsoft.Agents.AI.UnitTests.csproj' -f net472 -c Release --no-restore Passed: all 3,225 core unit tests, 0 failures, 0 skipped.
dotnet test --project 'tests\Microsoft.Agents.AI.UnitTests\Microsoft.Agents.AI.UnitTests.csproj' -f net10.0 -c Release --no-restore --filter-query '/*/*/BackgroundAgentsProviderTests/*' Passed: 60 background-agent tests, 0 failures, 0 skipped.
dotnet format 'tests\Microsoft.Agents.AI.UnitTests\Microsoft.Agents.AI.UnitTests.csproj' --no-restore --include 'tests\Microsoft.Agents.AI.UnitTests\Harness\BackgroundAgents\BackgroundAgentsProviderTests.cs' --verbosity minimal Passed.

Before the corresponding fixes, both reasoning-enabled filtering cases failed, and all eight local/service-managed, reasoning-on/off, streaming/non-streaming bounce-back cases reproduced an empty completion. All now pass. The full solution unit-test suite and live-provider scenarios were not run.

Related Issue

Fixes #7384.

No other open PR referencing #7384 was found.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Drop reasoning-only remnants only when tool content was filtered, preserve unfiltered content, and cover the model-free filter and mocked workflow paths.

Co-authored-by: Copilot <[email protected]>
Copilot-Session: c2b8751b-fffc-4069-ad5b-ebb5d3d4335d
Copilot AI balanced review requested due to automatic review settings October 7, 2026 17:17
@agent-framework-automation agent-framework-automation Bot added .NET Usage: [Issues, PRs], Target: .Net workflows Usage: [Issues, PRs], Target: Workflows labels Oct 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The closing reference would resolve #7384 while its confirmed same-turn bounce-back defect remains unfixed.

1 open finding
What changed in this PR

Fixes handoff filtering so reasoning-only remnants are not forwarded after tool content removal.

Changes:

  • Drops reasoning-only remnants after handoff/tool filtering.
  • Documents the behavior and adds preservation/regression coverage.
  • Extends orchestration tests to include reasoning responses.
File Description
HandoffMessagesFilter.cs Removes reasoning-only filtered remnants.
HandoffToolCallFilteringBehavior.cs Documents filtering semantics.
HandoffMessageFilterTests.cs Adds filtering and preservation tests.
HandoffOrchestrationTests.cs Tests reasoning-enabled handoffs.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MAF Automated Review — Iteration 1

Result: No findings
Scope: full PR (1 commit(s)): 890da44564a0
Model: gpt-5.6-sol

Overview

The PR narrowly removes reasoning-only remnants when handoff or tool content was actually filtered, while preserving standalone reasoning, visible text, unfiltered tools, and the None behavior. Per-invocation state, clone-before-mutation behavior, and unit plus end-to-end coverage constrain the change to handoff reception. No publishable Critical, High, or Medium issue was established.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

Keep the blocking runtime-lock holder off the thread pool and await continuation startup after releasing the lock, preserving the stale-waiter race assertions and existing timeout bounds.

Co-authored-by: Copilot <[email protected]>
Copilot-Session: c2b8751b-fffc-4069-ad5b-ebb5d3d4335d
@github-code-quality

github-code-quality Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: C#

C# / code-coverage/dotnet

main 95feea6 fix/handoff-reasonin... 3f7f72d +/-
86% 85% -1%
View coverage of the 4 most impacted files.
File main 95feea6 fix/handoff-reasonin... 3f7f72d +/-
/home/runner/wo...SessionStore.cs 100% 53% -47%
/home/runner/wo...erExtensions.cs 94% 94% 0%
/home/runner/wo...gentExecutor.cs 98% 98% 0%
/home/runner/wo...ssagesFilter.cs 89% 90% +1%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 14, 2026 16:23 UTC

Co-authored-by: Copilot <[email protected]>
Copilot-Session: c2b8751b-fffc-4069-ad5b-ebb5d3d4335d
@baywet Vincent Biret (baywet) changed the title .NET: Fix reasoning-only handoff message filtering .NET: Fix reasoning remnants and handoff bounce-back Oct 7, 2026
@baywet
Vincent Biret (baywet) requested a balanced review from Copilot October 7, 2026 19:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Stateful replay spans checkpoint restoration and provider-managed history, warranting final human validation despite broad tests.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation and regression coverage address both reported defects; remaining feedback is limited to minor convention fixes.

0 open findings

1 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Low severity Replace string comparison with ordinal string.Equals

dotnet/​tests/​Microsoft.Agents.AI.Workflows.UnitTests/​HandoffOrchestrationTests.cs:542

This new string comparison conflicts with the explicit repository rule in dotnet/AGENTS.md:43, which requires string.Equals with a StringComparison. Use an ordinal comparison for the call ID.

This issue also appears in the following locations of the same file:

  • line 551
  • line 621

🧠 Review effort: Balanced

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MAF Automated Review — Iteration 2

Result: Findings reported
Scope: 5 net-new commit(s): 1bdb623a3bda, c68ddfe5b418, aec53efa5332, 321c6f771649, 465ea91eea49
Model: gpt-5.6-sol

Overview

The change tracks each participant's pending handoff result and uses call-ID matching, fresh-input detection, participant-local state, and broad streaming/checkpoint tests to constrain when bounce-back recovery runs. Those guards prevent unrelated handoffs and ordinary tool continuations from triggering the recovery path. The residual risk is that recovery represents continuation by submitting the original user command as a new request, which can cause a returning agent to repeat side effects it already performed.

Reviewed the supplied incremental change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/HandoffAgentExecutor.cs

Co-authored-by: Copilot <[email protected]>
Copilot-Session: 31c9e0cd-1e8c-4c9e-acb8-8eada0af6797
@baywet
Vincent Biret (baywet) added this pull request to the merge queue Oct 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 14, 2026
@baywet
Vincent Biret (baywet) added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 74db3c1 Oct 14, 2026
36 checks passed
@baywet
Vincent Biret (baywet) deleted the fix/handoff-reasoning-filter-7384 branch October 14, 2026 16:46

This branch was previously deployed

2 inactive deployments
github-app-auth — 3f7f72dd Deployed Oct 14, 2026 by baywet via add_label #25338
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net workflows Usage: [Issues, PRs], Target: Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: AgentWorkflowBuilder Handoff orchestration breaks when handoffs bounce back, especially with reasoning

5 participants