Add a tool name replacement mapping for the generation of prompts

This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-06-12 20:15:00 +02:00
1 parent acee002dc4
commit 9abfc3d1be
8 files changed
+67 -17

No files matched your search

+3 -2
View File
@@ -14,8 +14,9 @@ Status of the `main` branch. Changes prior to the next official version change w
incorrect file access if a corresponding local file existed (e.g. `./antigravity` binary);
file access is now guarded with path detection (file ending or path separator must be present)
- Allow `query_project` tool to access read-only tools that are not enabled in the current configuration
- Fix: JetBrains mode prompt was not provided to agents; The mode is now treated as a (background) base mode
in `ActiveModes` which reduces the surface for issues pertaining to custom handling of modes.
- Adjust prompt generation mechanism to use newly introduced tool name mapping `tool_names`, allowing
prompts to directly use tool names that match the active language backend (and removing the need
for additional prompts that explain tool name differences)
- Improve quoting/escaping of arguments in shell executions on Windows (via `oslex` dependency)
* Language Servers:
+1
View File
@@ -284,6 +284,7 @@ ignore = [
"UP042", # wants str,Enum -> StrEnum (breaking change)
"PLW0108", # unnecessary lambda (style preference)
"PLC0207", # split vs rsplit optimization (style preference)
"RSE102", # wants to force use of raise with class instead of instance (style preference)
]
unfixable = ["F841", "F601", "F602", "B018"]
extend-fixable = ["F401", "B905", "W291"]
+31 -1
View File
@@ -647,6 +647,9 @@ class SerenaAgent:
else:
log.info(f"Using language backend from global configuration: {self._language_backend.name}")
# create the tool names mapping for prompts
self._prompt_tool_names_mapping = self._create_prompt_tool_names_mapping(self._language_backend)
# create executor for starting the language server and running tools in another thread
# This executor is used to achieve linear task execution
self._task_executor = TaskExecutor("SerenaAgentTaskExecutor", self._task_completion_callback)
@@ -927,9 +930,35 @@ class SerenaAgent:
"""
return self._active_modes
@staticmethod
def _create_prompt_tool_names_mapping(language_backend: LanguageBackend) -> dict[str, str]:
"""
Creates a mapping from tool names to new tool names, which take into consideration
* legacy tool names, where the name was changed and
* LSP tools which are functionally replaced by other tools due to the active language backend
(e.g. "find_symbol" being replaced by "jet_brains_find_symbol" in JetBrains mode).
The mapping is intended to be used for the generation of prompts, such that prompts can
refer to tool names as `{{ tool_names["find_symbol"] }}`, and the mapping will ensure that
the correct tool name is used in the prompt based on the active language backend.
:return: the mapping from tool names to new tool names
"""
result = dict(ToolSet.LEGACY_TOOL_NAME_MAPPING)
class_replacements = language_backend.get_lsp_tool_class_replacements()
for tool_class in ToolRegistry().get_all_tool_classes():
new_tool_class: type[Tool] = class_replacements.get(tool_class, tool_class)
result[tool_class.get_name_from_cls()] = new_tool_class.get_name_from_cls()
return result
def _format_prompt(self, prompt_template: str) -> str:
template = JinjaTemplate(prompt_template)
return template.render(available_tools=self._exposed_tools.tool_names, available_markers=self._exposed_tools.tool_marker_names)
return template.render(
available_tools=self._exposed_tools.tool_names,
available_markers=self._exposed_tools.tool_marker_names,
tool_names=self._prompt_tool_names_mapping,
)
def create_connection_prompt(self) -> str:
"""
@@ -969,6 +998,7 @@ class SerenaAgent:
available_tools=available_tools.tool_names,
available_markers=available_markers,
global_memories_list=global_memories_str,
tool_names=self._prompt_tool_names_mapping,
)
# provide the project activation message if it hasn't yet been provided
+23
View File
@@ -42,6 +42,7 @@ from ..util.dataclass import get_dataclass_default
if TYPE_CHECKING:
from ..project import Project
from ..tools.tools_base import Tool
log = logging.getLogger(__name__)
T = TypeVar("T")
@@ -217,6 +218,28 @@ class LanguageBackend(Enum):
def is_jetbrains(self) -> bool:
return self == LanguageBackend.JETBRAINS
def get_lsp_tool_class_replacements(self) -> "dict[type[Tool], type[Tool]]":
"""
:return: mapping from LSP tool classes to replacement tool classes (functional replacements)
"""
match self:
case LanguageBackend.LSP:
return {}
case LanguageBackend.JETBRAINS:
from ..tools import jetbrains_tools, symbol_tools
return {
symbol_tools.FindSymbolTool: jetbrains_tools.JetBrainsFindSymbolTool,
symbol_tools.GetSymbolsOverviewTool: jetbrains_tools.JetBrainsGetSymbolsOverviewTool,
symbol_tools.FindReferencingSymbolsTool: jetbrains_tools.JetBrainsFindReferencingSymbolsTool,
symbol_tools.FindImplementationsTool: jetbrains_tools.JetBrainsFindImplementationsTool,
symbol_tools.FindDeclarationTool: jetbrains_tools.JetBrainsFindDeclarationTool,
symbol_tools.RenameSymbolTool: jetbrains_tools.JetBrainsRenameTool,
symbol_tools.SafeDeleteSymbol: jetbrains_tools.JetBrainsSafeDeleteTool,
}
case _:
raise NotImplementedError()
class LineEnding(Enum):
"""Line ending convention for file writes."""
@@ -42,6 +42,7 @@ class PromptFactory(PromptFactoryBase):
context_system_prompt: Any,
global_memories_list: Any,
mode_system_prompts: Any,
tool_names: Any,
) -> str:
return self._render_prompt("system_prompt", locals())
@@ -1,11 +1,5 @@
description: JetBrains tools replace language server-based tools
prompt: |
You have access to the very powerful JetBrains tools for symbolic operations.
These partly replace regular tools you were informed about:
* `jet_brains_find_symbol` replaces `find_symbol`
* `jet_brains_find_referencing_symbols` replaces `find_referencing_symbols`
* `jet_brains_get_symbols_overview` replaces `get_symbols_overview`
* `jet_brains_rename` replaces `rename_symbol`
prompt:
excluded_tools:
- find_symbol
- find_referencing_symbols
@@ -21,9 +21,9 @@ prompt: |
If you need to replace the definition of a symbol, use the `replace_symbol_body` tool.
If you want to add some new code at the end of the file, use the `insert_after_symbol` tool with the last top-level symbol in the file.
Similarly, you can use `insert_before_symbol` with the first top-level symbol in the file to insert code at the beginning of a file.
You can understand relationships between symbols by using the `find_referencing_symbols` tool. If not explicitly requested otherwise by the user,
You can understand relationships between symbols by using the ``{{ tool_names['find_referencing_symbols'] }}`` tool. If not explicitly requested otherwise by the user,
you make sure that when you edit a symbol, the change is either backward-compatible or you find and update all references as needed.
The `find_referencing_symbols` tool will give you code snippets around the references as well as symbolic information.
The `{{ tool_names['find_referencing_symbols'] }}` tool will give you code snippets around the references as well as symbolic information.
You can assume that all symbol editing tools are reliable, so you never need to verify the results if the tools return without error.
{% if 'replace_content' in available_tools %}
@@ -26,14 +26,14 @@ prompts:
{% endif %}
{% if 'ToolMarkerSymbolicRead' in available_markers %}
Symbols are identified by their `name_path` and `relative_path` (see the description of the `find_symbol` tool).
You can get information about the symbols in a file by using the `get_symbols_overview` tool or use the `find_symbol` to search.
Symbols are identified by their `name_path` and `relative_path` (see the description of the `{{ tool_names['find_symbol'] }}` tool).
You can get information about the symbols in a file by using the `{{ tool_names['get_symbols_overview'] }}` tool or use the `{{ tool_names['find_symbol'] }}` to search.
You only read the bodies of symbols when you need to (e.g. if you want to fully understand or edit it).
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 name path pattern `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 name path pattern `Foo`, `include_body=False` and `depth=1` to get all (top-level) methods of `Foo` before proceeding
use `{{ tool_names['find_symbol'] }}` with name path pattern `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 `{{ tool_names['find_symbol'] }}` with name path pattern `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 understand relationships between symbols by using the `find_referencing_symbols` tool.
You can understand relationships between symbols by using the `{{ tool_names['find_referencing_symbols'] }}` tool.
{% endif %}
{% if 'read_memory' in available_tools -%}