Assert that a specific tool call occurred in the trajectory. When `step` is `None`, all steps are searched. When `step` is given, only that step (1-indexed) is checked. Attributes: name: Expected tool name. step: Optional 1-indexed step to restrict the search to.
| 669 | |
| 670 | @dataclass(frozen=True) |
| 671 | class ToolCall(EfficiencyAssertion): |
| 672 | """Assert that a specific tool call occurred in the trajectory. |
| 673 | |
| 674 | When `step` is `None`, all steps are searched. When `step` is given, |
| 675 | only that step (1-indexed) is checked. |
| 676 | |
| 677 | Attributes: |
| 678 | name: Expected tool name. |
| 679 | step: Optional 1-indexed step to restrict the search to. |
| 680 | args_contains: If set, the tool call args must contain these key-value pairs. |
| 681 | args_equals: If set, the tool call args must equal this dict exactly. |
| 682 | """ |
| 683 | |
| 684 | name: str |
| 685 | step: int | None = None |
| 686 | args_contains: dict[str, object] | None = None |
| 687 | args_equals: dict[str, object] | None = None |
| 688 | |
| 689 | def check(self, trajectory: AgentTrajectory) -> bool: |
| 690 | """Check that a matching tool call exists in the trajectory. |
| 691 | |
| 692 | Args: |
| 693 | trajectory: The agent trajectory to check. |
| 694 | |
| 695 | Returns: |
| 696 | Whether a matching tool call was found. |
| 697 | """ |
| 698 | return bool(self._find_matches(trajectory)) |
| 699 | |
| 700 | def describe_failure(self, trajectory: AgentTrajectory) -> str: |
| 701 | """Describe why the tool-call check failed. |
| 702 | |
| 703 | Args: |
| 704 | trajectory: The agent trajectory that failed the check. |
| 705 | |
| 706 | Returns: |
| 707 | A human-readable failure description. |
| 708 | """ |
| 709 | step_desc = f" in step {self.step}" if self.step is not None else "" |
| 710 | return f"Missing expected tool call{step_desc}: name={self.name!r}, args_contains={self.args_contains!r}, args_equals={self.args_equals!r}" |
| 711 | |
| 712 | def _matches_tool_call(self, tc: dict[str, object]) -> bool: |
| 713 | """Check whether a single tool call dict matches this expectation. |
| 714 | |
| 715 | Args: |
| 716 | tc: A tool call dictionary with `name` and `args` keys. |
| 717 | |
| 718 | Returns: |
| 719 | Whether the tool call matches. |
| 720 | """ |
| 721 | if tc.get("name") != self.name: |
| 722 | return False |
| 723 | if self.args_contains is not None: |
| 724 | args = tc.get("args") |
| 725 | if not isinstance(args, dict): |
| 726 | return False |
| 727 | if not all(args.get(k) == v for k, v in self.args_contains.items()): |
| 728 | return False |
no outgoing calls
searching dependent graphs…