Merge branch 'main' into v1-beta

This commit is contained in:
Dominik Jain committed 2026-04-03 13:58:03 +02:00
commit 620a226878
3 files changed
+47 -27

No files matched your search

+44 -3
View File
@@ -2,6 +2,7 @@
The Serena Model Context Protocol (MCP) Server
"""
import json
import multiprocessing
import os
import platform
@@ -35,7 +36,16 @@ from serena.ls_manager import LanguageServerManager
from serena.project import MemoriesManager, Project
from serena.prompt_factory import SerenaPromptFactory
from serena.task_executor import TaskExecutor
from serena.tools import ActivateProjectTool, GetCurrentConfigTool, OpenDashboardTool, ReplaceContentTool, Tool, ToolMarker, ToolRegistry
from serena.tools import (
ActivateProjectTool,
GetCurrentConfigTool,
OpenDashboardTool,
ReadMemoryTool,
ReplaceContentTool,
Tool,
ToolMarker,
ToolRegistry,
)
from serena.util.gui import system_has_usable_display
from serena.util.inspection import iter_subclasses
from serena.util.logging import MemoryLogHandler
@@ -81,6 +91,9 @@ class AvailableTools:
def contains_tool_name(self, tool_name: str) -> bool:
return tool_name in self._tool_name_set
def contains_tool_class(self, tool_class: type[Tool]) -> bool:
return self.contains_tool_name(tool_class.get_name_from_cls())
class ToolSet:
"""
@@ -579,7 +592,7 @@ class SerenaAgent:
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True, # Detach from parent process
start_new_session=False,
)
def get_exposed_tool_instances(self) -> list["Tool"]:
@@ -648,11 +661,39 @@ class SerenaAgent:
# If a project is active at startup, append its activation message
if self._active_project is not None:
system_prompt += "\n\n" + self._active_project.get_activation_message()
system_prompt += "\n\n" + self.get_project_activation_message()
log.info("System prompt:\n%s", system_prompt)
return system_prompt
def get_project_activation_message(self) -> str:
"""
:return: a message providing information about the project upon activation (e.g. programming language, memories, initial prompt)
:raise: AssertionError if no project is active
"""
proj = self._active_project
assert proj is not None, "A project must be active before calling this."
if proj.is_newly_created:
msg = f"Created and activated a new project with name '{proj.project_name}' at {proj.project_root}. "
else:
msg = f"The project with name '{proj.project_name}' at {proj.project_root} is activated."
if self._language_backend == LanguageBackend.LSP:
languages_str = ", ".join([lang.value for lang in proj.project_config.languages])
msg += f"\nProgramming languages: {languages_str}."
msg += "File encoding: {proj.project_config.encoding}."
include_memories = self._active_tools.contains_tool_class(ReadMemoryTool)
if include_memories:
project_memories = proj.memories_manager.list_project_memories()
if project_memories:
msg += (
f"\n{json.dumps(project_memories.to_dict())}\n"
+ "Use the `read_memory` tool to read these memories later if they are relevant to the task."
)
if proj.project_config.initial_prompt:
msg += f"\nAdditional project-specific instructions:\n {proj.project_config.initial_prompt}"
return msg
def _update_active_modes(self) -> None:
"""
Updates the active modes based on the Serena configuration, the active project configuration (if any),
+1 -22
View File
@@ -1,4 +1,3 @@
import json
import logging
import os
import re
@@ -291,7 +290,7 @@ class Project(ToStringMixin):
self.language_server_manager: LanguageServerManager | None = None
self._language_server_manager_init_error: Exception | None = None
self._is_newly_created = is_newly_created
self.is_newly_created = is_newly_created
self._agent: Optional["SerenaAgent"] = None
# create .gitignore file in the project's Serena data folder if not yet present
@@ -379,26 +378,6 @@ class Project(ToStringMixin):
def path_to_project_yml(self) -> str:
return self.serena_config.get_project_yml_location(self.project_root)
def get_activation_message(self) -> str:
"""
:return: a message providing information about the project upon activation (e.g. programming language, memories, initial prompt)
"""
if self._is_newly_created:
msg = f"Created and activated a new project with name '{self.project_name}' at {self.project_root}. "
else:
msg = f"The project with name '{self.project_name}' at {self.project_root} is activated."
languages_str = ", ".join([lang.value for lang in self.project_config.languages])
msg += f"\nProgramming languages: {languages_str}; file encoding: {self.project_config.encoding}"
project_memories = self.memories_manager.list_project_memories()
if project_memories:
msg += (
f"\nAvailable project memories: {json.dumps(project_memories.to_dict())}\n"
+ "Use the `read_memory` tool to read these memories later if they are relevant to the task."
)
if self.project_config.initial_prompt:
msg += f"\nAdditional project-specific instructions:\n {self.project_config.initial_prompt}"
return msg
def read_file(self, relative_path: str) -> str:
"""
Reads a file relative to the project root.
+2 -2
View File
@@ -28,8 +28,8 @@ class ActivateProjectTool(Tool, ToolMarkerDoesNotRequireActiveProject):
:param project: the name of a registered project to activate or a path to a project directory
"""
active_project = self.agent.activate_project_from_path_or_name(project)
result = active_project.get_activation_message()
self.agent.activate_project_from_path_or_name(project)
result = self.agent.get_project_activation_message()
result += "\nIMPORTANT: If you have not yet read the 'Serena Instructions Manual', do it now before continuing!"
return result