# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Asserts for checking tool calls."""

import re


def check_tool_used_with_args_match(_: str, context: dict) -> dict:
    """Checks if one of the given tools was used with arguments matching all of
    a list of regexes.

    The assertion should be in the format:
    - type: >
        python:path/to/this/file.py:check_tool_used_with_args_match
      config:
        args_regexes: [<regex1>, <regex2>, ...]
        tool_names: [<tool_name_1>, <tool_name_2>, ...]
    """
    config = context.get('config', {})
    args_regexes = config.get('args_regexes')
    if not args_regexes:
        return {
            'pass': False,
            'reason': (
                'No regexes specified in the `args_regexes` field of '
                'the assertion config.'
            ),
            'score': 0,
        }
    if isinstance(args_regexes, str):
        args_regexes = [args_regexes]
    tool_names = config.get('tool_names')
    if not tool_names:
        return {
            'pass': False,
            'reason': (
                'No tools specified in the `tool_names` field of the '
                'assertion config.'
            ),
            'score': 0,
        }
    if isinstance(tool_names, str):
        tool_names = [tool_names]
    tool_names = set(tool_names)

    provider_response = context.get('providerResponse', {})
    metrics = provider_response.get('metrics', {})
    tool_calls = metrics.get('tool_calls', [])

    tool_used = None
    for call in tool_calls:
        function_name = call.get('function_name')
        if function_name in tool_names:
            tool_used = function_name
            args_str = call.get('function_args', '')
            if not args_str:
                continue

            if all(re.search(regex, args_str) for regex in args_regexes):
                return {
                    'pass': True,
                    'reason': (
                        f'Tool "{function_name}" was used with '
                        'arguments matching all regexes.'
                    ),
                    'score': 1,
                }

    if not tool_used:
        used_tool_names = {c.get('function_name') for c in tool_calls}
        return {
            'pass': False,
            'reason': (
                f'None of the tools {sorted(tool_names)} were used. '
                f'Used tools: {sorted(list(used_tool_names))}'
            ),
            'score': 0,
        }

    # A tool was used, but no arguments matched the regex.
    return {
        'pass': False,
        'reason': (
            f'Tool "{tool_used}" was used, but its arguments did not '
            f'match all of the regexes: "{args_regexes}".'
        ),
        'score': 0,
    }
