Towards finalization of mode and context handling, WIP

This commit is contained in:
Michael Panchenko committed 2025-05-22 23:00:15 +02:00
1 parent 13a1d236dc
commit 494189ba16
6 files changed
+73 -68

No files matched your search

+2 -3
View File
@@ -8,7 +8,6 @@ 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.
{context_system_prompt}
{{ context_system_prompt }}
{mode_system_prompt}
{{ mode_system_prompt }}
+2 -2
View File
@@ -1,5 +1,5 @@
"""
Autogenerates the `prompt_factory.py` module
Autogenerates the `prompt_factory.py` module
"""
from pathlib import Path
@@ -15,7 +15,7 @@ log = logging.getLogger(__name__)
def main():
autogenerate_prompt_factory_module(
prompts_dir=PROMPT_TEMPLATES_DIR,
target_module_path=str(Path(REPO_ROOT) / "src" / "serena" / "prompt_factory.py"),
target_module_path=str(Path(REPO_ROOT) / "src" / "serena" / "generated" / "generated_prompt_factory.py"),
)
+3 -2
View File
@@ -357,11 +357,12 @@ def autogenerate_prompt_factory_module(prompts_dir: str, target_module_path: str
:param target_module_path: the path to the target module file. Important: The module will be overwritten!
"""
generated_code = """
# NOTE: This class is auto-generated from interprompt.autogenerate_prompt_factory_module, do not edit manually!
# ruff: noqa
# black: skip
# mypy: ignore-errors
# NOTE: This module is auto-generated from interprompt.autogenerate_prompt_factory_module, do not edit manually!
from interprompt.promt_template import PromptFactoryBase, PromptList
from typing import Any
@@ -390,7 +391,7 @@ class PromptFactory(PromptFactoryBase):
def get_list_{prompt_list_name}(self) -> PromptList:
return self._get_prompt_list('{prompt_list_name}')
"""
os.makedirs(os.path.dirname(target_module_path), exist_ok=True)
with open(target_module_path, "w", encoding="utf-8") as f:
f.write(generated_code)
log.info(f"Prompt factory generated successfully in {target_module_path}")
+26 -33
View File
@@ -29,7 +29,7 @@ from multilspy.multilspy_config import Language, MultilspyConfig
from multilspy.multilspy_logger import MultilspyLogger
from multilspy.multilspy_types import SymbolKind
from serena import serena_root_path, serena_version
from serena.prompt_factory import PromptFactory
from serena.prompt_factory import PromptFactory, SerenaPromptFactory
from serena.symbol import SymbolLocation, SymbolManager
from serena.text_utils import search_files
from serena.util.class_decorators import singleton
@@ -225,7 +225,7 @@ class SerenaAgent:
log.info("Available projects: {}".format(", ".join(self.serena_config.project_names)))
# Initialize the prompt factory
self.prompt_factory = PromptFactory()
self.prompt_factory = SerenaPromptFactory()
self._project_activation_callback = project_activation_callback
# Load context and mode configuration
@@ -311,20 +311,13 @@ class SerenaAgent:
:param context: Name or path of the context to use
"""
try:
context_config = self.config_loader.get_context(context)
self.current_context = context_config
context_config = self.config_loader.get_context(context)
self.current_context = context_config
# Update the prompt factory with the new context
self.prompt_factory.set_context(context_config.system_prompt_extension)
# Update tool configurations
self._update_active_tools()
# Update tool configurations
self._update_active_tools()
log.info(f"Set context to '{context_config.name}': {context_config.description}")
except Exception as e:
log.error(f"Failed to set context '{context}': {e}")
raise
log.info(f"Set context to '{context_config.name}': {context_config.description}")
def set_modes(self, modes: list[str]) -> None:
"""
@@ -332,29 +325,29 @@ class SerenaAgent:
:param modes: List of mode names or paths to use
"""
try:
# Check for tool activation conflicts between modes
mode_configs = [self.config_loader.get_mode(mode) for mode in modes]
mode_configs = [self.config_loader.get_mode(mode) for mode in modes]
self._check_mode_conflicts(mode_configs)
self.current_modes = mode_configs
self._update_active_tools()
# Check for conflicts in tool exclusions between modes
self._check_mode_conflicts(mode_configs)
log.info(f"Set modes to {[mode.name for mode in mode_configs]}")
self.current_modes = mode_configs
def _get_modes_system_prompt(self) -> str:
return "\n".join([mode.system_prompt_extension for mode in self.current_modes])
# Update the prompt factory with the new modes
mode_extensions = [mode.system_prompt_extension for mode in mode_configs]
self.prompt_factory.set_modes(mode_extensions)
def _get_context_system_prompt(self) -> str:
return self.current_context.system_prompt_extension
# Update tool configurations
self._update_active_tools()
def create_system_prompt(self) -> str:
context_system_prompt = self._get_context_system_prompt()
mode_system_prompt = self._get_modes_system_prompt()
return self.prompt_factory.create_system_prompt(
context_system_prompt=context_system_prompt,
mode_system_prompt=mode_system_prompt,
)
mode_names = [mode.name for mode in mode_configs]
log.info(f"Set modes to {mode_names}")
except Exception as e:
log.error(f"Failed to set modes {modes}: {e}")
raise
def _check_mode_conflicts(self, mode_configs: list["ConfigData"]) -> None:
@staticmethod
def _check_mode_conflicts(mode_configs: list["ConfigData"]) -> None:
"""
Check for conflicts in tool exclusions between modes.
@@ -1549,7 +1542,7 @@ class InitialInstructionsTool(Tool):
Get the initial instructions for the current coding project.
You should always call this tool before starting to work (including using any other tool) on any programming task!
"""
return self.agent.prompt_factory.create_system_prompt()
return self.agent.create_system_prompt()
def iter_tool_classes(same_module_only: bool = True) -> Generator[type[Tool], None, None]:
@@ -0,0 +1,35 @@
# ruff: noqa
# black: skip
# mypy: ignore-errors
# NOTE: This module is auto-generated from interprompt.autogenerate_prompt_factory_module, do not edit manually!
from interprompt.promt_template import PromptFactoryBase, PromptList
from typing import Any
class PromptFactory(PromptFactoryBase):
"""
A class for retrieving and rendering prompt templates and prompt lists.
"""
def create_onboarding_prompt(self, *, system: Any) -> str:
return self._render_prompt("onboarding_prompt", system=system)
def create_think_about_collected_information(self) -> str:
return self._render_prompt("think_about_collected_information")
def create_think_about_task_adherence(self) -> str:
return self._render_prompt("think_about_task_adherence")
def create_think_about_whether_you_are_done(self) -> str:
return self._render_prompt("think_about_whether_you_are_done")
def create_summarize_changes(self) -> str:
return self._render_prompt("summarize_changes")
def create_prepare_for_new_conversation(self) -> str:
return self._render_prompt("prepare_for_new_conversation")
def create_system_prompt(self, *, context_system_prompt: Any, mode_system_prompt: Any) -> str:
return self._render_prompt("system_prompt", context_system_prompt=context_system_prompt, mode_system_prompt=mode_system_prompt)
+5 -28
View File
@@ -1,34 +1,11 @@
from serena.constants import PROMPT_TEMPLATES_DIR
from serena.generated.generated_prompt_factory import PromptFactory
# NOTE: This class is auto-generated from interprompt.autogenerate_prompt_factory_module, do not edit manually!
# ruff: noqa
# black: skip
# mypy: ignore-errors
from interprompt.promt_template import PromptFactoryBase, PromptList
from typing import Any
class PromptFactory(PromptFactoryBase):
class SerenaPromptFactory(PromptFactory):
"""
A class for retrieving and rendering prompt templates and prompt lists.
"""
def create_onboarding_prompt(self, *, system: Any) -> str:
return self._render_prompt("onboarding_prompt", system=system)
def create_think_about_collected_information(self) -> str:
return self._render_prompt("think_about_collected_information")
def create_think_about_task_adherence(self) -> str:
return self._render_prompt("think_about_task_adherence")
def create_think_about_whether_you_are_done(self) -> str:
return self._render_prompt("think_about_whether_you_are_done")
def create_summarize_changes(self) -> str:
return self._render_prompt("summarize_changes")
def create_prepare_for_new_conversation(self) -> str:
return self._render_prompt("prepare_for_new_conversation")
def create_system_prompt(self) -> str:
return self._render_prompt("system_prompt")
def __init__(self):
super().__init__(PROMPT_TEMPLATES_DIR)