Repository navigation
.NET: add SignalProtocolLoopEvaluator for LoopAgent - #9163
Open
Mark Licata (marklicata) wants to merge 5 commits into
Open
Mark Licata (marklicata) wants to merge 5 commits into
Mark Licata (marklicata) wants to merge 5 commits into
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 15:34 — with
GitHub Actions
Inactive
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 15:34 — with
GitHub Actions
Inactive
5 tasks done
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 15:34 — with
GitHub Actions
Inactive
5 tasks done
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Signal matching includes non-assistant messages, and stale exit reasons can leak across iterations.
3 open findings
What changed in this PR
Adds typed signal-based termination for .NET LoopAgent.
Changes:
- Adds
SignalProtocolLoopEvaluatorandLoopExitReason. - Propagates non-streaming loop exit reasons.
- Adds evaluator tests and public API baselines.
| File | Description |
|---|---|
dotnet/src/Microsoft.Agents.AI/Harness/Loop/SignalProtocolLoopEvaluator.cs |
Implements signal detection. |
dotnet/src/Microsoft.Agents.AI/Harness/Loop/LoopExitReason.cs |
Defines exit-reason constants. |
dotnet/src/Microsoft.Agents.AI/Harness/Loop/LoopEvaluator.cs |
Documents the new evaluator. |
dotnet/src/Microsoft.Agents.AI/Harness/Loop/LoopAgent.cs |
Propagates exit metadata. |
dotnet/tests/Microsoft.Agents.AI.UnitTests/Harness/Loop/SignalProtocolLoopEvaluatorTests.cs |
Tests signal evaluation. |
dotnet/src/Microsoft.Agents.AI/PublicAPI/net8.0/PublicAPI.Unshipped.txt |
Records net8.0 APIs. |
dotnet/src/Microsoft.Agents.AI/PublicAPI/net9.0/PublicAPI.Unshipped.txt |
Records net9.0 APIs. |
dotnet/src/Microsoft.Agents.AI/PublicAPI/net10.0/PublicAPI.Unshipped.txt |
Records net10.0 APIs. |
dotnet/src/Microsoft.Agents.AI/PublicAPI/net472/PublicAPI.Unshipped.txt |
Records net472 APIs. |
dotnet/src/Microsoft.Agents.AI/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt |
Records netstandard2.0 APIs. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 15:37 — with
GitHub Actions
Inactive
Mark Licata (marklicata)
marked this pull request as ready for review
October 7, 2026 15:56
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 15:57 — with
GitHub Actions
Inactive
…exit reason Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 16:06 — with
GitHub Actions
Inactive
Mark Licata (marklicata)
had a problem deploying
to
integration
October 7, 2026 16:07 — with
GitHub Actions
Failure
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 7, 2026 16:22 — with
GitHub Actions
Inactive
SignalProtocolLoopEvaluator now only recognizes TASK_COMPLETE: / NEED_INPUT: when the token starts a line of an assistant message (optionally preceded by spaces or tabs). Mid-sentence or backtick-quoted mentions such as "I'll emit `TASK_COMPLETE:` when done" no longer stop the loop. Matches the Python signal protocol (microsoft#9162). DefaultFeedbackMessage now tells the model to start a new line with the token; the PublicAPI.Unshipped.txt entries are updated because the analyzer tracks const values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 13, 2026 16:36 — with
GitHub Actions
Inactive
Mark Licata (marklicata)
deployed
to
integration
October 13, 2026 16:36 — with
GitHub Actions
Active
Mark Licata (marklicata)
had a problem deploying
to
integration
October 13, 2026 16:36 — with
GitHub Actions
Failure
…-dotnet Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mark Licata (marklicata)
temporarily deployed
to
github-app-auth
October 13, 2026 16:45 — with
GitHub Actions
Inactive
Mark Licata (marklicata)
deployed
to
integration
October 13, 2026 16:47 — with
GitHub Actions
Active
Mark Licata (marklicata)
deployed
to
integration
October 13, 2026 16:47 — with
GitHub Actions
Active
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Motivation & Context
Agents running inside
LoopAgenthave no standard way to say "I'm done" or "I need a human". Each team writes its ownLoopEvaluator. This adds a text-based signal protocol so the agent can communicate loop termination intent directly in its response text:TASK_COMPLETE: <summary>: agent signals it is done; loop stopsNEED_INPUT: <question>: agent needs human input; loop stopsThis is the .NET half of the work previously proposed in #8993, split per language at the reviewers' request. The Python counterpart is #9162 and uses the same token strings and
loop_exit_reasonkey.Description & Review Guide
What are the major changes?
SignalProtocolLoopEvaluator: aLoopEvaluatormatching the token convention (ordinal comparison); stampscontext.AdditionalProperties["loop_exit_reason"]before returningStop()LoopExitReason:[Experimental]static class with const string values andAdditionalPropertiesKeyLoopAgent(non-streaming) stamps cap and evaluator-stop exit reasons on the returnedAgentResponse.AdditionalPropertiesPublicAPI.Unshipped.txtupdated for all 5 target frameworksWhat is the impact of these changes?
Additive and marked
[Experimental]. Consumers not usingSignalProtocolLoopEvaluatorsee no behavior change beyond the exit-reason stamp on non-streaming responses.What do you want reviewers to focus on?
LoopExitReasonXML docs)LoopAgentcurrently reportsiteration_cap_reached(carried over from an open review thread on Python: Python + .NET: add signal protocol for autonomous agent loops #8993)Related Issue
Part of #8860, together with #9162 for Python. The issue is closed manually once both PRs have merged.
Contribution Checklist
🤖 Generated with Claude Code