mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 12:15:10 +00:00
Merge branch 'main' of github.com:oraios/serena
This commit is contained in:
commit
3c0e8dc7ad
5 files changed
+52
-39
No files matched your search
@@ -26,4 +26,4 @@ if __name__ == "__main__":
|
||||
# apply a tool
|
||||
find_refs_tool = agent.get_tool(FindReferencingSymbolsTool)
|
||||
print("Finding the symbol 'SyncLanguageServer'\n")
|
||||
pprint(json.loads(find_refs_tool.apply(name_path="SyncLanguageServer", relative_file_path="src/multilspy/language_server.py")))
|
||||
pprint(json.loads(find_refs_tool.apply(name_path="SyncLanguageServer", relative_path="src/multilspy/language_server.py")))
|
||||
+21
-14
@@ -445,6 +445,8 @@ class MemoriesManagerMDFilesInProject(MemoriesManager):
|
||||
self._memory_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _get_memory_file_path(self, name: str) -> Path:
|
||||
# strip all .md from the name. Models tend to get confused, sometimes passing the .md extension and sometimes not.
|
||||
name = name.replace(".md", "")
|
||||
filename = f"{name}.md"
|
||||
return self._memory_dir / filename
|
||||
|
||||
@@ -462,7 +464,7 @@ class MemoriesManagerMDFilesInProject(MemoriesManager):
|
||||
return f"Memory {name} written."
|
||||
|
||||
def list_memories(self) -> list[str]:
|
||||
return [f.name for f in self._memory_dir.iterdir() if f.is_file()]
|
||||
return [f.name.replace(".md", "") for f in self._memory_dir.iterdir() if f.is_file()]
|
||||
|
||||
def delete_memory(self, name: str) -> str:
|
||||
memory_file_path = self._get_memory_file_path(name)
|
||||
@@ -1167,7 +1169,7 @@ class FindSymbolTool(Tool):
|
||||
self,
|
||||
name_path: str,
|
||||
depth: int = 0,
|
||||
within_relative_path: str | None = None,
|
||||
relative_path: str | None = None,
|
||||
include_body: bool = False,
|
||||
include_kinds: list[int] | None = None,
|
||||
exclude_kinds: list[int] | None = None,
|
||||
@@ -1207,7 +1209,11 @@ class FindSymbolTool(Tool):
|
||||
|
||||
:param name_path: The name path pattern to search for, see above for details.
|
||||
:param depth: Depth to retrieve descendants (e.g., 1 for class methods/attributes).
|
||||
:param within_relative_path: Optional. Restrict search to this file or directory. If None, searches entire codebase.
|
||||
:param relative_path: Optional. Restrict search to this file or directory. If None, searches entire codebase.
|
||||
If a directory is passed, the search will be restricted to the files in that directory.
|
||||
If a file is passed, the search will be restricted to that file.
|
||||
If you have some knowledge about the codebase, you should use this parameter, as it will significantly
|
||||
speed up the search as well as reduce the number of results.
|
||||
:param include_body: If True, include the symbol's source code. Use judiciously.
|
||||
:param include_kinds: Optional. List of LSP symbol kind integers to include. (e.g., 5 for Class, 12 for Function).
|
||||
Valid kinds: 1=file, 2=module, 3=namespace, 4=package, 5=class, 6=method, 7=property, 8=field, 9=constructor, 10=enum,
|
||||
@@ -1226,7 +1232,7 @@ class FindSymbolTool(Tool):
|
||||
include_kinds=parsed_include_kinds,
|
||||
exclude_kinds=parsed_exclude_kinds,
|
||||
substring_matching=substring_matching,
|
||||
within_relative_path=within_relative_path,
|
||||
within_relative_path=relative_path,
|
||||
)
|
||||
symbol_dicts = [s.to_dict(kind=True, location=True, depth=depth, include_body=include_body) for s in symbols]
|
||||
result = json.dumps(symbol_dicts)
|
||||
@@ -1241,7 +1247,7 @@ class FindReferencingSymbolsTool(Tool):
|
||||
def apply(
|
||||
self,
|
||||
name_path: str,
|
||||
relative_file_path: str,
|
||||
relative_path: str,
|
||||
include_kinds: list[int] | None = None,
|
||||
exclude_kinds: list[int] | None = None,
|
||||
max_answer_chars: int = _DEFAULT_MAX_ANSWER_LENGTH,
|
||||
@@ -1253,7 +1259,8 @@ class FindReferencingSymbolsTool(Tool):
|
||||
as subclasses are referencing symbols that have the kind class.
|
||||
|
||||
:param name_path: for finding the symbol to find references for, same logic as in the `find_symbol` tool.
|
||||
:param relative_file_path: the relative path to the file containing the symbol for which to find references.
|
||||
:param relative_path: the relative path to the file containing the symbol for which to find references.
|
||||
Note that here you can't pass a directory but must pass a file.
|
||||
:param include_kinds: same as in the `find_symbol` tool.
|
||||
:param exclude_kinds: same as in the `find_symbol` tool.
|
||||
:param max_answer_chars: same as in the `find_symbol` tool.
|
||||
@@ -1264,7 +1271,7 @@ class FindReferencingSymbolsTool(Tool):
|
||||
parsed_exclude_kinds: Sequence[SymbolKind] | None = [SymbolKind(k) for k in exclude_kinds] if exclude_kinds else None
|
||||
references_in_symbols = self.symbol_manager.find_referencing_symbols(
|
||||
name_path,
|
||||
relative_file_path=relative_file_path,
|
||||
relative_file_path=relative_path,
|
||||
include_body=include_body,
|
||||
include_kinds=parsed_include_kinds,
|
||||
exclude_kinds=parsed_exclude_kinds,
|
||||
@@ -1610,12 +1617,13 @@ class WriteMemoryTool(Tool):
|
||||
Writes a named memory (for future reference) to Serena's project-specific memory store.
|
||||
"""
|
||||
|
||||
def apply(self, memory_file_name: str, content: str, max_answer_chars: int = _DEFAULT_MAX_ANSWER_LENGTH) -> str:
|
||||
def apply(self, memory_name: str, content: str, max_answer_chars: int = _DEFAULT_MAX_ANSWER_LENGTH) -> str:
|
||||
"""
|
||||
Write some information about this project that can be useful for future tasks to a memory file.
|
||||
Write some information about this project that can be useful for future tasks to a memory.
|
||||
Use markdown formatting for the content.
|
||||
The information should be short and to the point.
|
||||
The memory file name should be meaningful, such that from the name you can infer what the information is about.
|
||||
It is better to have multiple small memory files than to have a single large one because
|
||||
The memory name should be meaningful, such that from the name you can infer what the information is about.
|
||||
It is better to have multiple small memories than to have a single large one because
|
||||
memories will be read one by one and we only ever want to read relevant memories.
|
||||
|
||||
This tool is either called during the onboarding process or when you have identified
|
||||
@@ -1623,11 +1631,10 @@ class WriteMemoryTool(Tool):
|
||||
"""
|
||||
if len(content) > max_answer_chars:
|
||||
raise ValueError(
|
||||
f"Content for {memory_file_name} is too long. Max length is {max_answer_chars} characters. "
|
||||
+ "Please make the content shorter."
|
||||
f"Content for {memory_name} is too long. Max length is {max_answer_chars} characters. " + "Please make the content shorter."
|
||||
)
|
||||
|
||||
return self.memories_manager.save_memory(memory_file_name, content)
|
||||
return self.memories_manager.save_memory(memory_name, content)
|
||||
|
||||
|
||||
class ReadMemoryTool(Tool):
|
||||
|
||||
@@ -3,27 +3,6 @@ prompt: |
|
||||
You are operating in planning mode. Your task is to analyze code but not write any code.
|
||||
The user may ask you to assist in creating a comprehensive plan, or to learn something about the codebase -
|
||||
either a small aspect of it or about the whole project.
|
||||
When reading code in order to answer a user question or task, you should try reading only the necessary code.
|
||||
Some tasks may require you to understand the architecture of large parts of the codebase, while for others,
|
||||
it may be enough to read a single file or a small set of symbols.
|
||||
You can achieve the intelligent reading of code by using the symbolic tools for getting an overview of symbols and
|
||||
the relations between them, and then only reading the bodies of symbols that are necessary to answer the question
|
||||
or complete the task. You can also use the standard tools like list_dir, find_file and search_for_pattern if you need to.
|
||||
|
||||
Symbols are identified by their name path and relative file path, see the description of the `find_symbols` tool for more details
|
||||
on how the `name_path` matches symbols.
|
||||
You can get information about available symbols by using the `get_symbols_overview` tool for finding top-level symbols in a file
|
||||
or directory, or by using `find_symbol` if you already know the symbol's name path. You generally try to read as little code as possible
|
||||
while still solving your task, meaning you only read the bodies when you need to, and after you have found the symbol you want to edit.
|
||||
For example, if you are working with python code and already know that you need to read the body of the constructor of the class Foo, you can directly
|
||||
use `find_symbol` with the name path `Foo/__init__` and `include_body=True`. If you don't know yet which methods in `Foo` you need to read or edit,
|
||||
you can use `find_symbol` with the name path `Foo`, `include_body=False` and `depth=1` to get all (top-level) methods of `Foo` before proceeding
|
||||
to read the desired methods with `include_body=True`
|
||||
You can unterstand relationships between symbols by using the `find_referencing_symbols` tool.
|
||||
|
||||
You generally have access to memories and it may be useful for you to read them, but also only if they help you
|
||||
to answer the question or complete the task. You can infer which memories are relevant to the current task by reading
|
||||
the memory names and descriptions.
|
||||
excluded_tools:
|
||||
- create_text_file
|
||||
- replace_symbol_body
|
||||
|
||||
@@ -8,6 +8,33 @@ prompts:
|
||||
files containing general information about the codebase. You operate in a frugal and intelligent manner, always
|
||||
keeping in mind to not read or generate content that is not needed for the task at hand.
|
||||
|
||||
When reading code in order to answer a user question or task, you should try reading only the necessary code.
|
||||
Some tasks may require you to understand the architecture of large parts of the codebase, while for others,
|
||||
it may be enough to read a single file or a small set of symbols.
|
||||
You can achieve the intelligent reading of code by using the symbolic tools for getting an overview of symbols and
|
||||
the relations between them, and then only reading the bodies of symbols that are necessary to answer the question
|
||||
or complete the task. You can also use the standard tools like list_dir, find_file and search_for_pattern if you need to.
|
||||
When tools allow it, you pass the `relative_path` parameter to restrict the search to a specific file or directory.
|
||||
For some tools, `relative_path` can only be a file path, so make sure to properly read the tool descriptions.
|
||||
If you are unsure about a symbol's name or location (to the extent that substring_matching for the symbol name is not enough), you can use the `search_for_pattern` tool, which allows fast
|
||||
and flexible search for patterns in the codebase. This way you can first find candidates for symbols or files,
|
||||
and then proceed with the symbolic tools.
|
||||
|
||||
Symbols are identified by their `name_path and `relative_path`, see the description of the `find_symbols` tool for more details
|
||||
on how the `name_path` matches symbols.
|
||||
You can get information about available symbols by using the `get_symbols_overview` tool for finding top-level symbols in a file
|
||||
or directory, or by using `find_symbol` if you already know the symbol's name path. You generally try to read as little code as possible
|
||||
while still solving your task, meaning you only read the bodies when you need to, and after you have found the symbol you want to edit.
|
||||
For example, if you are working with python code and already know that you need to read the body of the constructor of the class Foo, you can directly
|
||||
use `find_symbol` with the name path `Foo/__init__` and `include_body=True`. If you don't know yet which methods in `Foo` you need to read or edit,
|
||||
you can use `find_symbol` with the name path `Foo`, `include_body=False` and `depth=1` to get all (top-level) methods of `Foo` before proceeding
|
||||
to read the desired methods with `include_body=True`
|
||||
You can unterstand relationships between symbols by using the `find_referencing_symbols` tool.
|
||||
|
||||
You generally have access to memories and it may be useful for you to read them, but also only if they help you
|
||||
to answer the question or complete the task. You can infer which memories are relevant to the current task by reading
|
||||
the memory names and descriptions.
|
||||
|
||||
The context and modes of operation are described below. From them you can infer how to interact with your user
|
||||
and which tasks and kinds of interactions are expected of you.
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class TestSerenaAgent:
|
||||
agent = serena_agent
|
||||
# Find the symbol location first
|
||||
find_symbol_tool = agent.get_tool(FindSymbolTool)
|
||||
result = find_symbol_tool.apply(symbol_name, within_relative_path=def_file)
|
||||
result = find_symbol_tool.apply(symbol_name, relative_path=def_file)
|
||||
time.sleep(1)
|
||||
symbols = json.loads(result)
|
||||
# Find the definition location
|
||||
@@ -92,7 +92,7 @@ class TestSerenaAgent:
|
||||
# sel_start = def_symbol["location"]["selectionRange"]["start"]
|
||||
# Now find references
|
||||
find_refs_tool = agent.get_tool(FindReferencingSymbolsTool)
|
||||
result = find_refs_tool.apply(name_path=def_symbol["name_path"], relative_file_path=loc["relative_path"])
|
||||
result = find_refs_tool.apply(name_path=def_symbol["name_path"], relative_path=loc["relative_path"])
|
||||
refs = json.loads(result)
|
||||
assert any(
|
||||
ref["location"]["relative_path"] == ref_file for ref in refs
|
||||
@@ -178,7 +178,7 @@ class TestSerenaAgent:
|
||||
result = find_symbol_tool.apply(
|
||||
name_path=name_path,
|
||||
depth=0,
|
||||
within_relative_path=None,
|
||||
relative_path=None,
|
||||
include_body=False,
|
||||
include_kinds=None,
|
||||
exclude_kinds=None,
|
||||
|
||||
Reference in new issue
Block a user