Merge pull request #863 from oraios/improved_overview_tools

Improved overview tools
This commit is contained in:
Michael Panchenko authored and GitHub committed 2026-01-03 18:27:53 +07:00
commit 5e7d5469cf
3 files changed
+79 -9

No files matched your search

+3 -2
View File
@@ -178,11 +178,12 @@ class JetBrainsPluginClient(ToStringMixin):
request_data = {"namePath": name_path, "relativePath": relative_path}
return self._make_request("POST", "/findReferences", request_data)
def get_symbols_overview(self, relative_path: str) -> dict[str, Any]:
def get_symbols_overview(self, relative_path: str, depth: int) -> dict[str, Any]:
"""
:param relative_path: the relative path to a source file
:param depth: the depth of children to include (0 = no children)
"""
request_data = {"relativePath": relative_path}
request_data = {"relativePath": relative_path, "depth": depth}
return self._make_request("POST", "/getSymbolsOverview", request_data)
def rename_symbol(
+41 -5
View File
@@ -1,3 +1,6 @@
from collections import defaultdict
from typing import Any
from serena.tools import Tool, ToolMarkerOptional, ToolMarkerSymbolicRead
from serena.tools.jetbrains_plugin_client import JetBrainsPluginClient
@@ -98,9 +101,41 @@ class JetBrainsGetSymbolsOverviewTool(Tool, ToolMarkerSymbolicRead, ToolMarkerOp
Retrieves an overview of the top-level symbols within a specified file using the JetBrains backend
"""
@staticmethod
def _transform_symbols_to_compact_format(symbols: list[dict[str, Any]]) -> dict[str, list]:
"""
Transform symbol overview from verbose format to compact grouped format.
Groups symbols by kind and uses names instead of full symbol objects.
For symbols with children, creates nested dictionaries.
The name_path can be inferred from the hierarchical structure:
- Top-level symbols: name_path = name
- Nested symbols: name_path = parent_name + "/" + name
For example, "convert" under class "ProjectType" has name_path "ProjectType/convert".
"""
result = defaultdict(list)
for symbol in symbols:
kind = symbol.get("type", "Unknown")
name_path = symbol["name_path"]
name = name_path.split("/")[-1]
children = symbol.get("children", [])
if children:
# Symbol has children: create nested dict {name: children_dict}
children_dict = JetBrainsGetSymbolsOverviewTool._transform_symbols_to_compact_format(children)
result[kind].append({name: children_dict})
else:
# Symbol has no children: just add the name
result[kind].append(name)
return result
def apply(
self,
relative_path: str,
depth: int = 0,
max_answer_chars: int = -1,
) -> str:
"""
@@ -111,13 +146,14 @@ class JetBrainsGetSymbolsOverviewTool(Tool, ToolMarkerSymbolicRead, ToolMarkerOp
or by using the `list_dir` and `find_file` tools (or similar).
:param relative_path: the relative path to the file to get the overview of
:param depth: depth up to which descendants shall be retrieved (e.g., use 1 to also retrieve immediate children).
:param max_answer_chars: max characters for the JSON result. If exceeded, no content is returned.
-1 means the default value from the config will be used.
:return: a JSON object containing the symbols
:return: a JSON object containing the symbols grouped by kind in a compact format.
"""
with JetBrainsPluginClient.from_project(self.project) as client:
response_dict = client.get_symbols_overview(
relative_path=relative_path,
)
result = self._to_json(response_dict)
response_dict = client.get_symbols_overview(relative_path=relative_path, depth=depth)
symbols = response_dict["symbols"]
compact_symbols = self._transform_symbols_to_compact_format(symbols)
result = self._to_json(compact_symbols)
return self._limit_length(result, max_answer_chars)
+35 -2
View File
@@ -3,6 +3,7 @@ Language server-related tools
"""
import os
from collections import defaultdict
from collections.abc import Sequence
from copy import copy
from typing import Any
@@ -61,7 +62,7 @@ class GetSymbolsOverviewTool(Tool, ToolMarkerSymbolicRead):
:param max_answer_chars: if the overview is longer than this number of characters,
no content will be returned. -1 means the default value from the config will be used.
Don't adjust unless there is really no other way to get the content required for the task.
:return: a JSON object containing info about top-level symbols in the file
:return: a JSON object containing symbols grouped by kind in a compact format.
"""
symbol_retriever = self.create_language_server_symbol_retriever()
file_path = os.path.join(self.project.project_root, relative_path)
@@ -73,9 +74,41 @@ class GetSymbolsOverviewTool(Tool, ToolMarkerSymbolicRead):
if os.path.isdir(file_path):
raise ValueError(f"Expected a file path, but got a directory path: {relative_path}. ")
result = symbol_retriever.get_symbol_overview(relative_path, depth=depth)[relative_path]
result_json_str = self._to_json(result)
# Transform to compact format
compact_result = self._transform_symbols_to_compact_format(result)
result_json_str = self._to_json(compact_result)
return self._limit_length(result_json_str, max_answer_chars)
@staticmethod
def _transform_symbols_to_compact_format(symbols: list[dict[str, Any]]) -> dict[str, list]:
"""
Transform symbol overview from verbose format to compact grouped format.
Groups symbols by kind and uses names instead of full symbol objects.
For symbols with children, creates nested dictionaries.
The name_path can be inferred from the hierarchical structure:
- Top-level symbols: name_path = name
- Nested symbols: name_path = parent_name + "/" + name
For example, "convert" under class "ProjectType" has name_path "ProjectType/convert".
"""
result = defaultdict(list)
for symbol in symbols:
kind = symbol.get("kind", "Unknown")
name = symbol.get("name", "unknown")
children = symbol.get("children", [])
if children:
# Symbol has children: create nested dict {name: children_dict}
children_dict = GetSymbolsOverviewTool._transform_symbols_to_compact_format(children)
result[kind].append({name: children_dict})
else:
# Symbol has no children: just add the name
result[kind].append(name)
return result
class FindSymbolTool(Tool, ToolMarkerSymbolicRead):
"""