Repository navigation
FEAT: exhaustive tool matching, so ToolsCalled can say "and nothing else" - #4151
Open
WatchTree-19 wants to merge 1 commit into
Open
WatchTree-19 wants to merge 1 commit into
WatchTree-19 wants to merge 1 commit into
Conversation
…lse" ToolsCalled is a subset match, so a run that calls the required tools plus others satisfies it. Add exhaustive=True for an exact match: the named tools ran and no other tool did. With no tools it asks that no tool ran at all. One observed execution of an unnamed tool disproves the match, even from partial evidence; confirming it needs complete, fully correlated evidence. OtelToolCallScorer now downgrades only verdicts that rest on absence when a request carries no trace link, which leaves subset behaviour unchanged. MessageToolCallScorer can refute an exhaustive match from a stored execution but never confirm one. The flag is left out of serialization while false, so stored subset conditions keep their form and expectation fingerprint (pinned in a test).
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The new async test helper lacks the required _async suffix and Score return annotation, violating mandatory repository conventions.
1 open issue
What changed in this PR
Adds exhaustive tool matching to PyRIT’s scoring conditions, allowing checks that required tools—and no others—ran, including checks that no tools ran.
Changes:
- Adds
ToolsCalled.exhaustivewhile preserving existing subset serialization and fingerprints. - Updates trace and message scorers to distinguish observed extra calls from absence-based conclusions.
- Adds validation, scoring, replay, and correlation tests, plus documentation.
| File | Description |
|---|---|
tests/unit/score/test_otel_tool_call_scorer.py |
Tests exhaustive matching, evidence completeness, and replay. |
tests/unit/score/test_message_trace_scoring.py |
Tests exhaustive verdicts with unlinked requests. |
tests/unit/score/test_message_tool_call_scorer.py |
Tests exhaustive scoring from stored executions. |
tests/unit/models/test_condition.py |
Tests validation, round trips, and fingerprint compatibility. |
pyrit/score/true_false/otel_tool_call_scorer.py |
Adds exhaustive matching and absence-aware correlation handling. |
pyrit/score/true_false/message_tool_call_scorer.py |
Refutes exhaustive matches when extra executions are recorded. |
pyrit/models/score/condition.py |
Defines the exhaustive flag and permits empty exhaustive requirements. |
doc/code/scoring/5_tool_call_scorer.py |
Explains exhaustive matching and evidence requirements. |
doc/code/scoring/5_tool_call_scorer.ipynb |
Adds the corresponding notebook documentation. |
Review effort: Balanced
| } | ||
|
|
||
|
|
||
| async def _score_exhaustive(message: Message, *names: str): |
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.

Description
Answers open question 4 in the scorer contract design: can an expectation express "and nothing else"?
ToolsCalledis a subset match, so a run that calls the required tools plus others still satisfies it. This addsexhaustive=Truefor an exact match: the named tools ran and no other tool did. An exhaustive condition with no tools asks that no tool ran at all, which is the shape a least-privilege or confirmation-gate check needs.The evidence rules follow the existing asymmetry. One observed execution of an unnamed tool disproves the match, even from partial evidence. Confirming it needs complete, fully correlated evidence.
OtelToolCallScorernow downgrades only verdicts that rest on absence when a request carries no trace link, so subset behaviour is unchanged.MessageToolCallScorercan refute an exhaustive match from a stored execution of an unnamed tool but never confirm one, since stored messages cannot rule out other tools.The flag is left out of serialization while false, so stored subset conditions keep their form and expectation fingerprint, pinned in a test against main. The tool-call scorer docs gain a short section on exhaustive matching.
How it was tested
pytest tests/unit/score tests/unit/models tests/unit/common tests/unit/_code_execution tests/unit/output tests/unit/executor/attack -n 2: 11573 passed, 65 skipped.MessageToolCallScorerturns 1 test red; restoring the old "at least one tool" validator turns 7 red.