mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 18:16:10 +00:00
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.
This commit is contained in:
1 parent
1d020b9606
commit
dc9ea7a1c8
3 files changed
+42
-28
No files matched your search
@@ -14,6 +14,8 @@ 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.
|
||||
|
||||
* Language Servers:
|
||||
- `typescript_vts`: Add `initialization_options` setting in `ls_specific_settings.typescript_vts`.
|
||||
|
||||
+39
-27
@@ -210,7 +210,12 @@ class ToolSet:
|
||||
class ActiveModes:
|
||||
_mode_instances: dict[str, SerenaAgentMode] = {}
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, background_base_modes: Sequence[SerenaAgentMode] | None = None) -> None:
|
||||
"""
|
||||
:param background_base_modes: base modes that are always active in the background and will not be removed
|
||||
by applications of mode selection definitions via method `apply`
|
||||
"""
|
||||
self._background_base_modes = background_base_modes or []
|
||||
self._configured_base_modes: Sequence[str] | None = None
|
||||
self._configured_default_modes: Sequence[str] | None = None
|
||||
self._added_modes: set[str] = set()
|
||||
@@ -220,7 +225,7 @@ class ActiveModes:
|
||||
"""
|
||||
self._active_mode_names: Sequence[str] = []
|
||||
"""
|
||||
the full list of active mode names
|
||||
the full list of active mode names (not including background base modes)
|
||||
"""
|
||||
|
||||
def apply(self, mode_selection: ModeSelectionDefinition) -> None:
|
||||
@@ -245,6 +250,9 @@ class ActiveModes:
|
||||
self._active_mode_names = sorted(set(self._configured_base_modes or []) | self._dynamically_activated_mode_names)
|
||||
|
||||
def get_mode_names(self) -> Sequence[str]:
|
||||
"""
|
||||
:return: the ordered list of active mode names (not including the non-user-facing background base modes)
|
||||
"""
|
||||
return self._active_mode_names
|
||||
|
||||
@classmethod
|
||||
@@ -253,14 +261,22 @@ class ActiveModes:
|
||||
cls._mode_instances[mode_name] = SerenaAgentMode.load(mode_name)
|
||||
return cls._mode_instances[mode_name]
|
||||
|
||||
def get_modes(self) -> Sequence[SerenaAgentMode]:
|
||||
return [self.get_mode_instance(mode_name) for mode_name in self._active_mode_names]
|
||||
def get_modes(self, include_background_base_modes: bool = False) -> Sequence[SerenaAgentMode]:
|
||||
result: list[SerenaAgentMode] = []
|
||||
if include_background_base_modes:
|
||||
result.extend(self._background_base_modes)
|
||||
result.extend([self.get_mode_instance(mode_name) for mode_name in self._active_mode_names])
|
||||
return result
|
||||
|
||||
def get_dynamically_activated_modes(self) -> Sequence[SerenaAgentMode]:
|
||||
return [self.get_mode_instance(mode_name) for mode_name in self._dynamically_activated_mode_names]
|
||||
|
||||
def get_base_modes(self) -> Sequence[SerenaAgentMode]:
|
||||
return [self.get_mode_instance(mode_name) for mode_name in self._configured_base_modes or []]
|
||||
def get_base_modes(self, include_background_base_modes: bool = False) -> Sequence[SerenaAgentMode]:
|
||||
result: list[SerenaAgentMode] = []
|
||||
if include_background_base_modes:
|
||||
result.extend(self._background_base_modes)
|
||||
result.extend([self.get_mode_instance(mode_name) for mode_name in self._configured_base_modes or []])
|
||||
return result
|
||||
|
||||
|
||||
class ProjectPromptProvisionStatus:
|
||||
@@ -555,10 +571,6 @@ class SerenaAgent:
|
||||
# propagate configuration to other components
|
||||
self.serena_config.propagate_settings()
|
||||
|
||||
# initialise active modes (baseline modes prior to project activation)
|
||||
self._active_modes: ActiveModes
|
||||
self._update_active_modes(log_message=False)
|
||||
|
||||
# determine registered project to be activated (if any)
|
||||
registered_project_to_activate: RegisteredProject | None = (
|
||||
self.serena_config.get_registered_project(project, autoregister=True) if project is not None else None
|
||||
@@ -642,6 +654,10 @@ class SerenaAgent:
|
||||
# Initialize the prompt factory
|
||||
self.prompt_factory = SerenaPromptFactory()
|
||||
|
||||
# initialise active modes (baseline modes prior to project activation, allowing newly activated modes to be tracked)
|
||||
self._active_modes: ActiveModes
|
||||
self._update_active_modes(log_message=False)
|
||||
|
||||
# activate the given project (if any), also updating the active modes
|
||||
# Note: We cannot update the active tools yet, because the base toolset has not been computed yet
|
||||
# (and its computation depends on the active project)
|
||||
@@ -653,9 +669,7 @@ class SerenaAgent:
|
||||
self._update_active_modes()
|
||||
|
||||
# determine the base toolset defining the set of exposed tools (which e.g. the MCP shall see),
|
||||
self._base_toolset = self._create_base_toolset(
|
||||
self.serena_config, self._language_backend, self._context, self._active_modes, self._active_project
|
||||
)
|
||||
self._base_toolset = self._create_base_toolset(self.serena_config, self._context, self._active_modes, self._active_project)
|
||||
self._exposed_tools = self._base_toolset.to_available_tools(self._all_tools)
|
||||
log.info(f"Number of exposed tools: {len(self._exposed_tools)}. Exposed tools: {self._exposed_tools.tool_names}")
|
||||
|
||||
@@ -719,7 +733,6 @@ class SerenaAgent:
|
||||
def _create_base_toolset(
|
||||
cls,
|
||||
serena_config: SerenaConfig,
|
||||
language_backend: LanguageBackend,
|
||||
context: SerenaAgentContext,
|
||||
modes: ActiveModes,
|
||||
project: Project | None,
|
||||
@@ -730,9 +743,9 @@ class SerenaAgent:
|
||||
* dashboard availability/opening on launch
|
||||
* Serena config
|
||||
* the context (which is fixed for the session)
|
||||
* the optional tools enabled by initial modes
|
||||
* the base modes (including background base modes like JetBrains mode)
|
||||
* the optional tools enabled by initial dynamic modes
|
||||
* single-project mode reductions (if applicable)
|
||||
* JetBrains mode
|
||||
"""
|
||||
# determine whether to include the OpenDashboardTool based on the Serena configuration
|
||||
tool_inclusion_definitions: list[ToolInclusionDefinition] = []
|
||||
@@ -751,7 +764,7 @@ class SerenaAgent:
|
||||
|
||||
# consider modes
|
||||
# * base modes: These cannot be changed, so they are fully applied
|
||||
for base_mode in modes.get_base_modes():
|
||||
for base_mode in modes.get_base_modes(include_background_base_modes=True):
|
||||
tool_inclusion_definitions.append(base_mode)
|
||||
# * dynamically activated modes:
|
||||
# - When not in a single-project context, these modes can later be turned off,
|
||||
@@ -788,10 +801,6 @@ class SerenaAgent:
|
||||
)
|
||||
tool_inclusion_definitions.append(project.project_config)
|
||||
|
||||
# enabled the internal 'jetbrains' mode for the JetBrains backend
|
||||
if language_backend == LanguageBackend.JETBRAINS:
|
||||
tool_inclusion_definitions.append(SerenaAgentMode.from_name_internal("jetbrains"))
|
||||
|
||||
# compute the resulting tool set
|
||||
base_toolset = ToolSet.default().apply(*tool_inclusion_definitions)
|
||||
log.info(f"Number of exposed tools: {len(base_toolset)}")
|
||||
@@ -912,11 +921,11 @@ class SerenaAgent:
|
||||
raise ValueError("No active project. Please activate a project first.")
|
||||
return project
|
||||
|
||||
def get_active_modes(self) -> list[SerenaAgentMode]:
|
||||
def get_active_modes(self) -> ActiveModes:
|
||||
"""
|
||||
:return: the list of active modes
|
||||
:return: the active modes
|
||||
"""
|
||||
return list(self._active_modes.get_modes())
|
||||
return self._active_modes
|
||||
|
||||
def _format_prompt(self, prompt_template: str) -> str:
|
||||
template = JinjaTemplate(prompt_template)
|
||||
@@ -948,7 +957,7 @@ class SerenaAgent:
|
||||
# determine modes for which prompts must (still) be provided, excluding modes that were already provided in a
|
||||
# previously provided project activation message (if any)
|
||||
relevant_modes = []
|
||||
for mode in self.get_active_modes():
|
||||
for mode in self.get_active_modes().get_modes(include_background_base_modes=True):
|
||||
if mode.has_prompt():
|
||||
if not self._project_prompt_status.is_mode_prompt_already_provided(mode.name, session_id):
|
||||
relevant_modes.append(mode)
|
||||
@@ -1027,7 +1036,10 @@ class SerenaAgent:
|
||||
Updates the active modes based on the Serena configuration, the active project configuration (if any),
|
||||
and mode overrides (if any).
|
||||
"""
|
||||
self._active_modes = ActiveModes()
|
||||
background_base_modes = []
|
||||
if self._language_backend.is_jetbrains():
|
||||
background_base_modes.append(SerenaAgentMode.from_name_internal("jetbrains"))
|
||||
self._active_modes = ActiveModes(background_base_modes=background_base_modes)
|
||||
self._active_modes.apply(self.serena_config)
|
||||
if self._active_project:
|
||||
self._active_modes.apply(self._active_project.project_config)
|
||||
@@ -1260,7 +1272,7 @@ class SerenaAgent:
|
||||
result_str += f"Active context: {self._context.name}\n"
|
||||
|
||||
# Active modes
|
||||
active_mode_names = [mode.name for mode in self.get_active_modes()]
|
||||
active_mode_names = self.get_active_modes().get_mode_names()
|
||||
result_str += "Active modes: {}\n".format(", ".join(active_mode_names)) + "\n"
|
||||
|
||||
# Available but not active modes
|
||||
|
||||
@@ -502,7 +502,7 @@ class SerenaDashboardAPI:
|
||||
}
|
||||
|
||||
# Get active modes
|
||||
modes = self._agent.get_active_modes()
|
||||
modes = self._agent.get_active_modes().get_modes(include_background_base_modes=False)
|
||||
modes_info = [
|
||||
{"name": mode.name, "description": mode.description, "path": SerenaAgentMode.get_path(mode.name, instance=mode)}
|
||||
for mode in modes
|
||||
|
||||
Reference in new issue
Block a user