commit c5b59a6cb87a093327b3bc2bbfa2a485a3b18d1f
  Author: Dominik Jain <dominik.jain@outlook.com>
  Date:   Sun Nov 23 18:53:06 2025 +0100

      ToolRegistry: Allow valid tool packages to be modified

  src-serena/serena/tools/tools_base.py

  commit 9b4299d4f3e12fe67919e304d9e33c527ee0f345
  Author: Dominik Jain <dominik.jain@outlook.com>
  Date:   Sun Nov 23 17:47:39 2025 +0100

      ToolInclusionDefinition: Add option to specify a fixed tool set

  src-serena/serena/agent.py
  src-serena/serena/config/serena_config.py
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2025-11-23 22:29:53 +01:00
1 parent d58dbebce2
commit 9781710f4e
3 files changed
+60 -24

No files matched your search

+29 -20
View File
@@ -106,26 +106,35 @@ class ToolSet:
registry = ToolRegistry()
tool_names = set(self._tool_names)
for definition in tool_inclusion_definitions:
included_tools = []
excluded_tools = []
for included_tool in definition.included_optional_tools:
included_tool = get_updated_tool_name(included_tool)
if not registry.is_valid_tool_name(included_tool):
raise ValueError(f"Invalid tool name '{included_tool}' provided for inclusion")
if included_tool not in tool_names:
tool_names.add(included_tool)
included_tools.append(included_tool)
for excluded_tool in definition.excluded_tools:
excluded_tool = get_updated_tool_name(excluded_tool)
if not registry.is_valid_tool_name(excluded_tool):
raise ValueError(f"Invalid tool name '{excluded_tool}' provided for exclusion")
if excluded_tool in tool_names:
tool_names.remove(excluded_tool)
excluded_tools.append(excluded_tool)
if included_tools:
log.info(f"{definition} included {len(included_tools)} tools: {', '.join(included_tools)}")
if excluded_tools:
log.info(f"{definition} excluded {len(excluded_tools)} tools: {', '.join(excluded_tools)}")
if definition.is_fixed_tool_set():
tool_names = set()
for fixed_tool in definition.fixed_tools:
fixed_tool = get_updated_tool_name(fixed_tool)
if not registry.is_valid_tool_name(fixed_tool):
raise ValueError(f"Invalid tool name '{fixed_tool}' provided for fixed tool set")
tool_names.add(fixed_tool)
log.info(f"{definition} defined a fixed tool set with {len(tool_names)} tools: {', '.join(tool_names)}")
else:
included_tools = []
excluded_tools = []
for included_tool in definition.included_optional_tools:
included_tool = get_updated_tool_name(included_tool)
if not registry.is_valid_tool_name(included_tool):
raise ValueError(f"Invalid tool name '{included_tool}' provided for inclusion")
if included_tool not in tool_names:
tool_names.add(included_tool)
included_tools.append(included_tool)
for excluded_tool in definition.excluded_tools:
excluded_tool = get_updated_tool_name(excluded_tool)
if not registry.is_valid_tool_name(excluded_tool):
raise ValueError(f"Invalid tool name '{excluded_tool}' provided for exclusion")
if excluded_tool in tool_names:
tool_names.remove(excluded_tool)
excluded_tools.append(excluded_tool)
if included_tools:
log.info(f"{definition} included {len(included_tools)} tools: {', '.join(included_tools)}")
if excluded_tools:
log.info(f"{definition} excluded {len(excluded_tools)} tools: {', '.join(excluded_tools)}")
return ToolSet(tool_names)
def without_editing_tools(self) -> "ToolSet":
+27 -3
View File
@@ -5,7 +5,7 @@ The Serena Model Context Protocol (MCP) Server
import dataclasses
import os
import shutil
from collections.abc import Iterable
from collections.abc import Sequence
from copy import deepcopy
from dataclasses import dataclass, field
from datetime import datetime
@@ -72,8 +72,32 @@ class SerenaPaths:
@dataclass
class ToolInclusionDefinition:
excluded_tools: Iterable[str] = ()
included_optional_tools: Iterable[str] = ()
"""
Defines which tools to include/exclude in Serena's operation.
This can mean either
* defining exclusions/inclusions to apply to an existing set of tools [incremental mode], or
* defining a fixed set of tools to use [fixed mode].
"""
excluded_tools: Sequence[str] = ()
"""
the names of tools to exclude from use [incremental mode]
"""
included_optional_tools: Sequence[str] = ()
"""
the names of optional tools to include [incremental mode]
"""
fixed_tools: Sequence[str] = ()
"""
the names of tools to use as a fixed set of tools [fixed mode]
"""
def is_fixed_tool_set(self) -> bool:
num_fixed = len(self.fixed_tools)
num_incremental = len(self.excluded_tools) + len(self.included_optional_tools)
if num_fixed > 0 and num_incremental > 0:
raise ValueError("Cannot use both fixed_tools and excluded_tools/included_optional_tools at the same time.")
return num_fixed > 0
class SerenaConfigError(Exception):
+4 -1
View File
@@ -350,12 +350,15 @@ class RegisteredTool:
tool_name: str
tool_packages = ["serena.tools"]
@singleton
class ToolRegistry:
def __init__(self) -> None:
self._tool_dict: dict[str, RegisteredTool] = {}
for cls in iter_subclasses(Tool):
if not cls.__module__.startswith("serena.tools"):
if not any(cls.__module__.startswith(pkg) for pkg in tool_packages):
continue
is_optional = issubclass(cls, ToolMarkerOptional)
name = cls.get_name_from_cls()