Repository navigation
Conversation
… the judge Since Azure#49804, a list of text messages was reported as not applicable without a judge call unless its text held this evaluator's [TOOL_CALL] or [TOOL_RESULT] markers. A transcript in another text format, such as ReAct Action and Observation lines or <tool_call> tags, was left out of the pass rate, together with its failed tool calls. Text that contains tool_call, tool_result, tool_response, function_call or function_result in any letter case, Llama's <|python_tag|> or <function= tags, the gpt-oss <|call|> token, or a line that starts with a label such as Action:, Observation:, Tool call: or Tool result: now counts as a tool transcript. Such a list goes to the judge model as its text, with each message's role and every tool definition, as a string does, because Decision-1 answered not applicable for ReAct steps inside a list of messages but judged the same text correctly. Also corrects the 1.18.11 CHANGELOG entries for error_kind, the score check and binary_aggregate.
|
Azure Pipelines: Successfully started running 1 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues remain for the changes restoring evaluation of recognized free-text tool transcripts.
No open issues 🎉
What changed in this PR
Restores judging of recognized free-text tool transcripts inside message lists in azure-ai-evaluation, addressing the applicability regression introduced by #49804 while preserving the no-judge path for plain text.
Changes:
- Detects common tool transcript markers and step labels, and sends matching text-only message lists to the judge with roles and all tool definitions.
- Adds regression coverage for transcript formats, message shapes, judge inputs, and aggregate scoring.
- Documents the supported formats and corrects existing release-note descriptions.
| File | Description |
|---|---|
sdk/evaluation/azure-ai-evaluation/tests/unittests/test_tool_call_success_evaluator.py |
Adds transcript detection, formatting, and scoring regression tests. |
sdk/evaluation/azure-ai-evaluation/CHANGELOG.md |
Documents transcript support and clarifies related release notes. |
sdk/evaluation/azure-ai-evaluation/azure/ai/evaluation/_evaluators/_tool_call_success/_tool_call_success.py |
Shares text extraction logic and routes recognized transcripts to the judge as role-labeled text. |
Review effort: Balanced
A Decision evaluator that the judge model rates as not applicable gave the reason "Status completion probability 0.2000 is below 0.5000; evaluation skipped.", which names an internal question. After the "Not applicable: " prefix it now reads "the judge model's applicability probability 0.2000 is below the 0.5000 cutoff, so the evaluator was skipped.", with the same numbers.
added 2 commits
November 4, 2026 20:21
1.18.11 shipped without this change, so its transcript handling and readable skip reason are listed under 1.18.12 (Unreleased), and the 1.18.11 Tool Call Success entry again describes what 1.18.11 does. The wording fixes to three other 1.18.11 entries stay there, since they describe 1.18.11.
…ecision reasons TaskAdherenceEvaluator with a Decision model reported threshold 0 by default although its binary result passes only at 1; it now reports 1, as _TaskCompletionEvaluator does. A requested threshold is still reported as given. Decision reasons named a question by its whole key, so the hosted service's rubric keys such as grade/confirm_details read "Grade/confirm details probability ...". They now use the part after the last slash.
…n Tool Call Success A line such as "1) Action:", "(2) Observation:", "a) Action:" or a bulleted or no-break-space indented label, and a label with a fullwidth colon, now count as a tool transcript. The text of a message that preprocessing drops for holding an MCP approval request no longer makes a list applicable, because no judge input includes it. Structured tool calls beside an approval still go to the judge.
Rabah B (RabsB)
approved these changes
Nov 6, 2026
This branch has not been 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.

Follow-up to #49804. 1.18.11 shipped without this change, so it targets 1.18.12.
#49804 made
_ToolCallSuccessEvaluatorreport a list of messages that holds only text as not applicable without calling the judge model. Text with this evaluator's own[TOOL_CALL]or[TOOL_RESULT]markers still went to the judge, but a tool transcript in any other text format did not. A ReAct agent'sAction:andObservation:steps, or a model's raw<tool_call>tags, inside a message list came back not applicable, so a failed tool call written that way was left out of the pass rate. In 1.18.10 these lists went to the judge.Changes
tool_call,tool_result,tool_response,function_callorfunction_resultin any letter case, which covers tags such as<tool_call>,<tool_response>,[TOOL_CALLS]and<function_calls>as well as this evaluator's own markers. Llama's<|python_tag|>and<function=tags, the gpt-oss<|call|>token, and a line that starts with a label such asAction:,Observation:,Tool call:orTool result:also count; the labels may carry step numbers and Markdown decoration. Messages of every role are checked, so a tool result passed as a user message counts.1),(2)ora), after indentation with non-breaking spaces, and with a fullwidth colon. Prose such as(action: see below),a) The next action:andReaction:still does not count.role: textblock per message, with every tool definition, as a string does. Before, the judge got the raw list. In live checks, Decision-1 answered not applicable for a ReAct transcript inside a list that also held the user's question, both for a failed and a successful call, but judged the same text correctly. Messages that hold an MCP approval are still left out, as preprocessing leaves them out of every judge input. Their text no longer counts as a transcript either, so a list whose only transcript text is in such a message stays not applicable without a judge call._has_no_tool_callsand the new_tool_transcriptshare one helper,_texts_of_text_messages, so the rules for what counts as a text message stay in one place.Not applicable: the judge model's applicability probability 0.2000 is below the 0.5000 cutoff, so the evaluator was skipped. No model rationale is available.It used to readStatus completion probability 0.2000 is below 0.5000; evaluation skipped., which named an internal question. Only the wording changes; the cutoff, the numbers and the not applicable result are the same./. The evaluation service grades Boolean rubric dimensions throughBinaryScoringwith keys such asgrade/confirm_details, so its reasons readGrade/confirm details probability 0.1645 is below the 0.7500 cutoff.; they now readConfirm details probability 0.1645 is below the 0.7500 cutoff.The SDK's own question keys have no/, so its reasons are unchanged.TaskAdherenceEvaluatorwith a Decision model reports threshold 1 when none is requested, the only score at which its binary result passes, as_TaskCompletionEvaluatorand the other binary evaluators do. It reported 0, below the catalog evaluator's own minimum of 1. A requested threshold is still reported as given and does not decide whether a binary result passes. Thethresholdattribute also defaults to 1 for chat models; chat results still report 3._version.pyto 1.18.12, and keeps the 1.18.11 Tool Call Success entry as it shipped. It also corrects three other 1.18.11 entries found in review. Theerror_kindentry now says when the kind appears in the error message, the score check entry no longer says it matches_ToolInputAccuracyEvaluator, and thebinary_aggregateentry says the last result column whose values can be counted decides.Strings, structured tool calls and lists in other formats are unchanged. The Microsoft Foundry portal and the evaluation service run their own copy of this evaluator, so they are not affected. The service's copy of Task adherence in azureml-assets also defaults to 0 and needs the same change there. The service takes the reason label fix when it moves to 1.18.12, since it calls
BinaryScoringfrom this package.Behavior
Action:andObservation:steps,<tool_call>tags,[TOOL_CALLS], LangChain's printed "Tool Calls:"[TOOL_CALL]or[TOOL_RESULT]Testing
tests/unitteststest_builtin_decision_evaluators.py,test_decision_*.py) after the skip reason changeevaluate()with ReAct failure, ReAct success, plain text and Hermes failure rowsbinary_aggregate0.33tool_calls, have an "Action:" line, or have a Markdown "Observation:" bulletmodel_dump()fields, MCP approval rows andevaluate()with mixed rowsbinary_aggregate0.5-W)_ToolCallSuccessEvaluatoris not in the generated docsAdded with the reason label and Task adherence threshold changes (e9fb612):
tests/unittests/,grade/, 100,000 characters, non-ASCII/are unchanged, and non-string keys raise as beforeTaskAdherenceEvaluatorwithout a threshold, withthreshold=0, and on a plainly adherent answerAdded with the list marker and MCP approval text changes (93ec9a0):
tests/unittests1),(2),a)and a bullet, with non-breaking space indentation and a fullwidth colon; prose such as(action: see below),a) The next action:andReaction:; MCP approval text alone and beside a user turn1)and bulleted transcripts in message listsNot changed