From 7a1dcfeeda4d639dd04ea131ffe2cce4c2781a63 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 15 Mar 2026 17:24:04 +0100 Subject: [PATCH] Auto-generate the tool list in the documentation --- docs/01-about/.gitignore | 1 + docs/01-about/035_tools.md | 49 ------------------------ docs/_config.yml | 2 +- docs/{autogen_rst.py => autogen_docs.py} | 30 +++++++++++++++ pyproject.toml | 4 +- src/serena/tools/tools_base.py | 22 +++++++++++ 6 files changed, 56 insertions(+), 52 deletions(-) create mode 100644 docs/01-about/.gitignore delete mode 100644 docs/01-about/035_tools.md rename docs/{autogen_rst.py => autogen_docs.py} (80%) diff --git a/docs/01-about/.gitignore b/docs/01-about/.gitignore new file mode 100644 index 00000000..e1fbb867 --- /dev/null +++ b/docs/01-about/.gitignore @@ -0,0 +1 @@ +/035_tools.md \ No newline at end of file diff --git a/docs/01-about/035_tools.md b/docs/01-about/035_tools.md deleted file mode 100644 index 293651e6..00000000 --- a/docs/01-about/035_tools.md +++ /dev/null @@ -1,49 +0,0 @@ -# List of Tools - -Find the full list of Serena's tools below (output of ` tools list --all`). - -Note that in most configurations, only a subset of these tools will be enabled simultaneously (see the section on [configuration](../02-usage/050_configuration) for details). -* `activate_project`: Activates a project based on the project name or path. -* `check_onboarding_performed`: Checks whether project onboarding was already performed. -* `create_text_file`: Creates/overwrites a file in the project directory. -* `delete_lines`: Deletes a range of lines within a file. -* `delete_memory`: Deletes a memory from Serena's project-specific memory store. -* `edit_memory`: -* `execute_shell_command`: Executes a shell command. -* `find_file`: Finds files in the given relative paths -* `find_referencing_symbols`: Finds symbols that reference the given symbol using the language server backend -* `find_symbol`: Performs a global (or local) search using the language server backend. -* `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes. -* `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file. -* `initial_instructions`: Provides instructions on how to use the Serena toolbox. - Should only be used in settings where the system prompt is not read automatically by the client. - - NOTE: Some MCP clients (including Claude Desktop) do not read the system prompt automatically! -* `insert_after_symbol`: Inserts content after the end of the definition of a given symbol. -* `insert_at_line`: Inserts content at a given line in a file. -* `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol. -* `jet_brains_find_referencing_symbols`: Finds symbols that reference the given symbol using the JetBrains backend -* `jet_brains_find_symbol`: Performs a global (or local) search for symbols using the JetBrains backend -* `jet_brains_get_symbols_overview`: Retrieves an overview of the top-level symbols within a specified file using the JetBrains backend -* `jet_brains_type_hierarchy`: Retrieves the type hierarchy (supertypes and/or subtypes) of a symbol using the JetBrains backend -* `list_dir`: Lists files and directories in the given directory (optionally with recursion). -* `list_memories`: Lists memories in Serena's project-specific memory store. -* `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building). -* `open_dashboard`: Opens the Serena web dashboard in the default web browser. - The dashboard provides logs, session information, and tool usage statistics. -* `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context). -* `read_file`: Reads a file within the project directory. -* `read_memory`: Reads the memory with the given name from Serena's project-specific memory store. -* `remove_project`: Removes a project from the Serena configuration. -* `rename_symbol`: Renames a symbol throughout the codebase using language server refactoring capabilities. -* `replace_content`: Replaces content in a file (optionally using regular expressions). -* `replace_lines`: Replaces a range of lines within a file with new content. -* `replace_symbol_body`: Replaces the full definition of a symbol using the language server backend. -* `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen. -* `search_for_pattern`: Performs a search for a pattern in the project. -* `summarize_changes`: Provides instructions for summarizing the changes made to the codebase. -* `switch_modes`: Activates modes by providing a list of their names -* `think_about_collected_information`: Thinking tool for pondering the completeness of collected information. -* `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task. -* `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed. -* `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store. \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml index 89a0f6c2..999c6a62 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -12,7 +12,7 @@ title : Serena Documentation # The title of the book. Wil author : Oraios AI & Oraios Software # The author of the book copyright : "2025 by Serena contributors" # Copyright year to be placed in the footer # Patterns to skip when building the book. Can be glob-style (e.g. "*skip.ipynb") -exclude_patterns : ['**.ipynb_checkpoints', '.DS_Store', 'Thumbs.db', '_build', 'jupyter_execute', '.jupyter_cache', '.pytest_cache', 'docs/autogen_rst.py', 'docs/create_toc.py'] +exclude_patterns : ['**.ipynb_checkpoints', '.DS_Store', 'Thumbs.db', '_build', 'jupyter_execute', '.jupyter_cache', '.pytest_cache', 'docs/autogen_docs.py', 'docs/create_toc.py'] # Auto-exclude files not in the toc only_build_toc_files : true diff --git a/docs/autogen_rst.py b/docs/autogen_docs.py similarity index 80% rename from docs/autogen_rst.py rename to docs/autogen_docs.py index e59c2f70..5b4ca422 100644 --- a/docs/autogen_rst.py +++ b/docs/autogen_docs.py @@ -4,6 +4,8 @@ import shutil from pathlib import Path from typing import Optional, List +from sensai.util.string import TextBuilder + log = logging.getLogger(os.path.basename(__file__)) TOP_LEVEL_PACKAGE = "serena" @@ -143,10 +145,38 @@ def make_rst(src_root, rst_root, clean=False, overwrite=False, package_prefix="" write_to_file(module_template(module_qualname), module_rst_path) +def autogen_tool_list(target_filename = "01-about/035_tools.md"): + from serena.tools import ToolRegistry + + target_file = Path(__file__).parent / target_filename + with open(target_file, "w") as f: + f.write("\n\n") + f.write("# Tools\n\n") + f.write("Find the full list of Serena's tools below. \n") + f.write("Note that in most configurations, only a subset of these tools will be enabled simultaneously.\n") + f.write("Tools marked as optional are disabled by default.\n\n") + tools_by_module = ToolRegistry().get_registered_tools_by_module() + priority_modules = {"serena.tools.symbol_tools": 1, "serena.tools.jetbrains_tools": 2} + + text = TextBuilder() + sorted_modules = sorted(tools_by_module.keys(), key=lambda m: (priority_modules.get(m, 3), m)) + for module in sorted_modules: + tools = tools_by_module[module] + module = module.replace("serena.tools.", "") + text.with_line(f"* **{module}**") + for tool in tools: + info = " *(optional)*" if tool.is_optional else "" + text.with_line(f"* `{tool.tool_name}`{info}: {tool.class_docstring}", indent=2) + f.write(text.build()) + + if __name__ == "__main__": logging.basicConfig(level=logging.INFO) docs_root = Path(__file__).parent enable_module_docs = False + + autogen_tool_list() + if enable_module_docs: make_rst( docs_root / ".." / "src" / "serena", diff --git a/pyproject.toml b/pyproject.toml index 35ab28f9..ccc5fa1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,12 +145,12 @@ _mypy_core = "mypy src/serena src/solidlsp" _mypy_test = "mypy --disable-error-code no-untyped-def test" type-check = ["_mypy_core", "_mypy_test"] # docs -_autogen_rst = "python docs/autogen_rst.py" +_autogen_docs = "python docs/autogen_docs.py" _sphinx_build = "sphinx-build -b html docs docs/_build -W --keep-going" _jb_generate_toc = "python docs/create_toc.py" _jb_generate_config = "jupyter-book config sphinx docs/" doc-clean = "rm -rf docs/_build docs/03_api" -doc-generate-files = ["_autogen_rst", "_jb_generate_toc", "_jb_generate_config"] +doc-generate-files = ["_autogen_docs", "_jb_generate_toc", "_jb_generate_config"] doc-build = ["doc-clean", "doc-generate-files", "_sphinx_build"] [tool.ruff] diff --git a/src/serena/tools/tools_base.py b/src/serena/tools/tools_base.py index 807005df..503ab341 100644 --- a/src/serena/tools/tools_base.py +++ b/src/serena/tools/tools_base.py @@ -382,6 +382,13 @@ class RegisteredTool: is_optional: bool tool_name: str + @property + def class_docstring(self) -> str: + """ + :return: the tool description (high-level class docstring) + """ + return self.tool_class.get_tool_description() + tool_packages = ["serena.tools"] @@ -400,6 +407,21 @@ class ToolRegistry: raise ValueError(f"Duplicate tool name found: {name}. Tool classes must have unique names.") self._tool_dict[name] = RegisteredTool(tool_class=cls, is_optional=is_optional, tool_name=name) + def get_registered_tools_by_module(self) -> dict[str, list[RegisteredTool]]: + """ + :return: the registered tools grouped by their module (ordered alphabetically by module and tool name) + """ + module_dict: dict[str, list[RegisteredTool]] = {} + for tool in self._tool_dict.values(): + module = tool.tool_class.__module__ + if module not in module_dict: + module_dict[module] = [] + module_dict[module].append(tool) + sorted_module_dict = {} + for module in sorted(module_dict.keys()): + sorted_module_dict[module] = sorted(module_dict[module], key=lambda t: t.tool_name) + return sorted_module_dict + def get_tool_class_by_name(self, tool_name: str) -> type[Tool]: if tool_name not in self._tool_dict: raise ValueError(f"Tool named '{tool_name}' not found.")