| 42 | |
| 43 | @dataclass |
| 44 | class Tool: |
| 45 | name: str |
| 46 | input_schema: Mapping[str, Any] |
| 47 | call: Callable[[dict[str, Any], ToolContext], ToolResult] |
| 48 | prompt: Callable[..., str] |
| 49 | description: Callable[[dict[str, Any]], str] |
| 50 | map_result_to_api: Callable[[Any, str], dict[str, Any]] |
| 51 | check_permissions: Callable[[dict[str, Any], ToolContext], PermissionResult] |
| 52 | is_enabled: Callable[[], bool] |
| 53 | is_concurrency_safe: Callable[[dict[str, Any]], bool] |
| 54 | is_read_only: Callable[[dict[str, Any]], bool] |
| 55 | is_destructive: Callable[[dict[str, Any]], bool] |
| 56 | user_facing_name: Callable[[dict[str, Any] | None], str] |
| 57 | to_auto_classifier_input: Callable[[dict[str, Any]], Any] |
| 58 | |
| 59 | aliases: tuple[str, ...] = () |
| 60 | search_hint: str | None = None |
| 61 | # ``int | float`` because FileReadTool declares ``float("inf")`` to |
| 62 | # opt out of result persistence (see ch06-tools.md "FileReadTool: |
| 63 | # The Versatile Reader" -- persisting Read output would create a |
| 64 | # circular Read loop). ``get_persistence_threshold`` special-cases |
| 65 | # ``math.inf`` to pass it through unchanged. |
| 66 | max_result_size_chars: int | float = 20_000 |
| 67 | strict: bool = False |
| 68 | should_defer: bool = False |
| 69 | always_load: bool = False |
| 70 | is_mcp: bool = False |
| 71 | is_lsp: bool = False |
| 72 | |
| 73 | validate_input: Callable[[dict[str, Any], ToolContext], ValidationResult] | None = None |
| 74 | get_path: Callable[[dict[str, Any]], str] | None = None |
| 75 | input_json_schema: Mapping[str, Any] | None = None |
| 76 | mcp_info: McpInfo | None = None |
| 77 | |
| 78 | interrupt_behavior: Callable[[], Literal["cancel", "block"]] | None = None |
| 79 | is_search_or_read_command: Callable[[dict[str, Any]], SearchOrReadResult] | None = None |
| 80 | is_open_world: Callable[[dict[str, Any]], bool] | None = None |
| 81 | requires_user_interaction: Callable[[], bool] | None = None |
| 82 | inputs_equivalent: Callable[[dict[str, Any], dict[str, Any]], bool] | None = None |
| 83 | backfill_observable_input: Callable[[dict[str, Any]], None] | None = None |
| 84 | prepare_permission_matcher: Callable[[dict[str, Any]], Callable[[str], bool]] | None = None |
| 85 | get_tool_use_summary: Callable[[dict[str, Any] | None], str | None] | None = None |
| 86 | get_activity_description: Callable[[dict[str, Any] | None], str | None] | None = None |
| 87 | |
| 88 | def matches_name(self, name: str) -> bool: |
| 89 | return self.name == name or name in self.aliases |
| 90 | |
| 91 | |
| 92 | Tools = list[Tool] |