A set of function tools that can be used in function calling. This class provides methods to add, remove, and retrieve tools, as well as convert the tools to different API formats (OpenAI, Anthropic, Google GenAI).
| 76 | |
| 77 | @dataclass |
| 78 | class ToolSet: |
| 79 | """A set of function tools that can be used in function calling. |
| 80 | |
| 81 | This class provides methods to add, remove, and retrieve tools, as well as |
| 82 | convert the tools to different API formats (OpenAI, Anthropic, Google GenAI). |
| 83 | """ |
| 84 | |
| 85 | tools: list[FunctionTool] = Field(default_factory=list) |
| 86 | |
| 87 | def empty(self) -> bool: |
| 88 | """Check if the tool set is empty.""" |
| 89 | return len(self.tools) == 0 |
| 90 | |
| 91 | def add_tool(self, tool: FunctionTool) -> None: |
| 92 | """Add a tool to the set. |
| 93 | |
| 94 | If a tool with the same name already exists: |
| 95 | - Prefer the one that is active (active=True) |
| 96 | - If both have the same active state, use the new one (overwrite) |
| 97 | """ |
| 98 | for i, existing_tool in enumerate(self.tools): |
| 99 | if existing_tool.name == tool.name: |
| 100 | # Use getattr with a default of True for compatibility with tools |
| 101 | # that may not define an `active` attribute (e.g., mocks). |
| 102 | existing_active = bool(getattr(existing_tool, "active", True)) |
| 103 | new_active = bool(getattr(tool, "active", True)) |
| 104 | # Overwrite if new tool is active, or if existing tool is not active |
| 105 | if new_active or not existing_active: |
| 106 | self.tools[i] = tool |
| 107 | return |
| 108 | self.tools.append(tool) |
| 109 | |
| 110 | def remove_tool(self, name: str) -> None: |
| 111 | """Remove a tool by its name.""" |
| 112 | self.tools = [tool for tool in self.tools if tool.name != name] |
| 113 | |
| 114 | def get_tool(self, name: str) -> FunctionTool | None: |
| 115 | """Get a tool by its name.""" |
| 116 | for tool in self.tools: |
| 117 | if tool.name == name: |
| 118 | return tool |
| 119 | return None |
| 120 | |
| 121 | def get_light_tool_set(self) -> "ToolSet": |
| 122 | """Return a light tool set with only name/description.""" |
| 123 | light_tools = [] |
| 124 | for tool in self.tools: |
| 125 | if hasattr(tool, "active") and not tool.active: |
| 126 | continue |
| 127 | light_params = { |
| 128 | "type": "object", |
| 129 | "properties": {}, |
| 130 | } |
| 131 | light_tools.append( |
| 132 | FunctionTool( |
| 133 | name=tool.name, |
| 134 | parameters=light_params, |
| 135 | description=tool.description, |
no outgoing calls