Repository navigation
Python: .NET: [Bug]: ContainsExpected reports missing expected output as a model failure #9019
Copy link
Copy link
Open
Labels
.NETUsage: [Issues, PRs], Target: .NetUsage: [Issues, PRs], Target: .NetagentsUsage: [Issues, PRs], Target: Single agentUsage: [Issues, PRs], Target: Single agentpythonUsage: [Issues, PRs], Target: PythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflowUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
Description
Activity
- added.NETUsage: [Issues, PRs], Target: .NetUsage: [Issues, PRs], Target: .NetpythonUsage: [Issues, PRs], Target: PythonUsage: [Issues, PRs], Target: PythontriageUsage: [Issues], Target: All issues that still need to be triagedUsage: [Issues], Target: All issues that still need to be triaged
on Oct 3, 2026 - changed the title
[-].NET: [Bug]: `ContainsExpected` reports missing expected output as a model failure[/-][+]Python: .NET: [Bug]: `ContainsExpected` reports missing expected output as a model failure[/+]on Oct 3, 2026 - addedreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflowUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
on Oct 3, 2026 🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
The bug reproduces in
dotnet/src/Microsoft.Agents.AI/Evaluation/EvalChecks.cs::ContainsExpectedwhenEvalItem.ExpectedOutputis null or empty; it returns a failed result thatLocalEvaluatormaps to an unacceptable metric. Minimal repro: create anEvalItemwithoutExpectedOutput, invokeEvalChecks.ContainsExpected(), and assert that configuration is surfaced before metric production.- Failing test:
dotnet/tests/Microsoft.Agents.AI.UnitTests/EvaluationDefectRegressionTests.cs - Files examined: dotnet/src/Microsoft.Agents.AI/Evaluation/EvalItem.cs, dotnet/src/Microsoft.Agents.AI/Evaluation/EvalChecks.cs, dotnet/src/Microsoft.Agents.AI/Evaluation/LocalEvaluator.cs, dotnet/tests/Microsoft.Agents.AI.UnitTests/EvaluationTests.cs
- Tests run: EvaluationTests.ContainsExpected_FailsWhenNoExpectedOutput, EvaluationDefectRegressionTests.ContainsExpected_WithoutExpectedOutput_ThrowsConfigurationError
- Failing test:
- addedagentsUsage: [Issues, PRs], Target: Single agentUsage: [Issues, PRs], Target: Single agentand removedtriageUsage: [Issues], Target: All issues that still need to be triagedUsage: [Issues], Target: All issues that still need to be triaged
on Oct 3, 2026 joslat commented
on Oct 3, 2026 ContributorAuthorMore actionsA draft implementation is available for an early look on the fix/eval-result-consistency branch, currently at commit f830367b9. No PR has been opened yet; I am waiting for maintainer feedback on the intended behavior before polishing and opening the combined PR.
Metadata
Metadata
Assignees
Labels
.NETUsage: [Issues, PRs], Target: .NetUsage: [Issues, PRs], Target: .NetagentsUsage: [Issues, PRs], Target: Single agentUsage: [Issues, PRs], Target: Single agentpythonUsage: [Issues, PRs], Target: PythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflowUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
Type
Projects
- StatusShow more project fieldsNo status
Summary
EvalChecks.ContainsExpected()returns a failed check whenEvalItem.ExpectedOutputis null or empty, even though the check cannot be applied. This turns a missing test fixture into a failed agent evaluation and is inconsistent with the built-in expected-tool-call check, which treats absent expectations as non-failing.Version and evidence
Reproduced from
mainat commite9857bd75a21843803431a2e7dfa41ee9b017ac7on 2026-10-03.ExpectedOutputis nullable indotnet/src/Microsoft.Agents.AI/Evaluation/EvalItem.cs:108-114.ContainsExpectedmaps null or emptyExpectedOutputtoEvalCheckResult(false, "ExpectedOutput is not set; check cannot be applied.", ...)indotnet/src/Microsoft.Agents.AI/Evaluation/EvalChecks.cs:219-243.LocalEvaluatorconverts any false check result into a failedBooleanMetricindotnet/src/Microsoft.Agents.AI/Evaluation/LocalEvaluator.cs:43-58.ToolCallArgsMatchexplicitly passes whenExpectedToolCallsis null or empty inEvalChecks.cs:126-146.dotnet/tests/Microsoft.Agents.AI.UnitTests/EvaluationTests.cs:1510-1518.Package version: source build at the SHA above. The reproduction was compiled for
net10.0and run with .NET SDK 10.0.400; the repository pins 10.0.401.Minimal reproduction
Proposed xUnit regression test in
dotnet/tests/Microsoft.Agents.AI.UnitTests/EvaluationDefectRegressionTests.cs:Run with:
The test fails with
Assert.Throws() Failure: No exception was thrown; the returned result hasPassed == falseand reasonExpectedOutput is not set; check cannot be applied.Actual behavior
A missing fixture produces an ordinary failed check, and
LocalEvaluatorreports it as an agent evaluation failure (EvalChecks.cs:224-242,LocalEvaluator.cs:43-58).ToolCallArgsMatchuses the opposite missing-input policy and returns a passing check (EvalChecks.cs:138-146).Expected behavior
Missing
ExpectedOutputshould be surfaced as test/evaluator configuration, not as evidence that the agent failed. The regression test expresses the recommended behavior: throw a clearInvalidOperationExceptionbefore an evaluation metric is produced.Impact
Any test suite that conditionally supplies expected outputs can produce false model failures when one fixture is omitted. CI output points maintainers toward the agent response even though the actionable defect is in the test data; this is especially confusing because the reason itself says that the check could not be applied (
EvalChecks.cs:228-230).Python parity
Python has no built-in
contains_expectedcheck. Function-evaluator injection converts missingexpected_outputto""inpython/packages/core/agent_framework/_evaluation.py:1253-1301, and its focused test asserts that conversion inpython/packages/core/tests/core/test_local_eval.py:127-149. Python's expected-tool-call checks pass when no expectations are supplied in_evaluation.py:1141-1164and_evaluation.py:1183-1208, so Python does not have the same built-in failure behavior.Duplicate search
No open or closed issue or PR matched
ContainsExpected. A broaderExpectedOutput "not set"search only surfaced unrelated sample PR #5823, which is not a duplicate.Fix options
InvalidOperationExceptionwhenExpectedOutputis null or empty. This is an observable behavior change for invalid/missing fixtures, but it changes no signature and requires noPublicAPI.Shipped.txtorPublicAPI.Unshipped.txtupdate;ContainsExpectedis already shipped indotnet/src/Microsoft.Agents.AI/PublicAPI/net10.0/PublicAPI.Shipped.txt:946.ToolCallArgsMatch. This is also a behavior change with no public API baseline change and is convenient for mixed datasets, but it can silently hide an accidentally missing fixture.EvalCheckResultand teachLocalEvaluatorhow to aggregate it. This gives the most precise diagnostics, butEvalCheckResultis a shipped public record inPublicAPI.Shipped.txt:295-305; changing its primary constructor/deconstructor would be a public API break, while an additive property would requirePublicAPI.Unshipped.txtentries and more aggregation design.I recommend option 1 because it fails fast on the real problem without silently accepting incomplete fixtures or changing public API. I would be happy to submit a PR with the regression test and a documented missing-input policy for the built-in checks.