diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 1a3b040a..8e97440d 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -55,10 +55,6 @@ jobs: run: uv pip install -e ".[dev]" - name: Test with pytest shell: bash - # Currently java Language Server is not working on macos + # Currently, java and rust seem to cause problems in CI run: | - if [ "${{ matrix.os }}" = "macos-latest" ]; then - uv run pytest -m "not java" - else - uv run poe test - fi + uv run pytest -m "not java and not rust" diff --git a/README.md b/README.md index c8948dcf..6d48de76 100644 --- a/README.md +++ b/README.md @@ -173,19 +173,31 @@ Serena can be used in various ways, below you will find instructions for selecte ### Setup -1. Install `uv` (instructions [here](https://docs.astral.sh/uv/getting-started/installation/)) -2. Clone the repository. -3. Copy `serena_config.template.yml` to `serena_config.yml` +Serena is managed by `uv`, so you will need to [install it](https://docs.astral.sh/uv/getting-started/installation/)). + +Then you can either + +1. Clone the repository and cd into it. +2. Optionally create a config file from the template and adjust it according to your preferences. ```shell - cp serena_config.template.yml serena_config.yml + cp src/serena/resources/serena_config.template.yml serena_config.yml ``` - + If you just want the default config, you can skip this part, and a config file will be created when you first run Serena. + +or use `uvx` to run Serena directly by relying on + +```shell +uvx --from git+https://github.com/oraios/serena serena-mcp-server.exe +``` + +in your MCP config (delete the `.exe` on macOS or Linux). + You can now add Serena to your MCP client as described below for various clients and [activate your first project](#project-activation). > In the default configuration, Serena will start a small dashboard on localhost that will display logs and allow shutting down the > MCP server (since many clients fail to cleanup processes, leaving zombies behind). If you don't want that, simply set `web_dashboard` to `False` -> in your `serena_config.yml`. +> in your `serena_config.yml` or pass ### Configuration @@ -195,7 +207,7 @@ Serena's behavior (like available projects, active tools and prompts) is configu 2. In the arguments passed to the `serena-mcp-server` in your client's config (see below), which will apply to all sessions started by the respective client. In particular, the [context](#contexts) parameter should be set appropriately for Serena to be best adjusted to existing tools and capabilities of your client. - See for a detailed explanation. + See for a detailed explanation. You can override all entries from the `serena_config.yml` through command line arguments. 3. In the `.serena/project.yml` file within your project. This will hold project-level configuration that is used whenever that project is activated. 4. Through the currently active set of [modes](#modes). @@ -253,6 +265,16 @@ That's it! Save the config and then restart Claude Desktop. You are ready for ac uv run serena-mcp-server --help ``` +ℹ️ You can use Serena without cloning or configuring it explicitly by + +{ + "mcpServers": { + "serena": { + "command": "/abs/path/to/uv", + "args": ["run", "--directory", "/abs/path/to/serena", "serena-mcp-server"] + } + } +} #### Troubleshooting diff --git a/pyproject.toml b/pyproject.toml index f66c7e58..d865d89e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ dependencies = [ "dotenv>=0.9.9", "pathspec>=0.12.1", "psutil>=7.0.0", - "agno>=1.2.15", "docstring_parser>=0.16", "joblib>=1.5.1", ] @@ -73,7 +72,7 @@ google = [ Homepage = "https://github.com/oraios/serena" [tool.hatch.build.targets.wheel] -packages = ["src/serena", "src/multilspy"] +packages = ["src/serena", "src/multilspy", "src/interprompt"] [tool.black] line-length = 140 diff --git a/src/serena/__init__.py b/src/serena/__init__.py index 3e1a38d7..1a6b2383 100644 --- a/src/serena/__init__.py +++ b/src/serena/__init__.py @@ -1,12 +1,6 @@ __version__ = "2025-05-21" -def serena_root_path() -> str: - from pathlib import Path - - return str(Path(__file__).parent.parent.parent.absolute()) - - def serena_version() -> str: """ :return: the version of the package, including git status if available. diff --git a/src/serena/agent.py b/src/serena/agent.py index 59b98f13..039174c7 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -21,7 +21,7 @@ from functools import cached_property from logging import Logger from pathlib import Path from types import TracebackType -from typing import TYPE_CHECKING, Any, Self, TypeVar, Union +from typing import TYPE_CHECKING, Any, Literal, Self, TypeVar, Union, cast import yaml from overrides import override @@ -34,9 +34,9 @@ from multilspy import SyncLanguageServer 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 import serena_version from serena.config import SerenaAgentContext, SerenaAgentMode -from serena.constants import PROJECT_TEMPLATE_FILE, SERENA_MANAGED_DIR_NAME +from serena.constants import PROJECT_TEMPLATE_FILE, REPO_ROOT, SELENA_CONFIG_TEMPLATE_FILE, SERENA_MANAGED_DIR_NAME from serena.dashboard import MemoryLogHandler, SerenaDashboardAPI from serena.prompt_factory import PromptFactory, SerenaPromptFactory from serena.symbol import SymbolManager @@ -297,17 +297,29 @@ class SerenaConfig(SerenaConfigBase): CONFIG_FILE = "serena_config.yml" @classmethod - def get_config_file_path(cls) -> str: - return os.path.join(serena_root_path(), cls.CONFIG_FILE) + def autogenerate(cls) -> None: + log.info("Autogenerating Serena configuration file") + if os.path.exists(cls.get_config_file_path()): + raise FileExistsError( + f"Serena configuration file already exists at {cls.get_config_file_path()}. Please remove it if you want to autogenerate a new one." + ) + loaded_commented_yaml = load_yaml(SELENA_CONFIG_TEMPLATE_FILE, preserve_comments=True) + save_yaml(cls.get_config_file_path(), loaded_commented_yaml, preserve_comments=True) @classmethod - def from_config_file(cls) -> "SerenaConfig": + def get_config_file_path(cls) -> str: + return os.path.join(REPO_ROOT, cls.CONFIG_FILE) + + @classmethod + def from_config_file(cls, generate_if_missing: bool = True) -> "SerenaConfig": """ Static constructor to create SerenaConfig from the configuration file """ config_file = cls.get_config_file_path() if not os.path.exists(config_file): - raise FileNotFoundError(f"Serena configuration file not found: {config_file}") + if not generate_if_missing: + raise FileNotFoundError(f"Serena configuration file not found: {config_file}") + cls.autogenerate() log.info(f"Loading Serena configuration from {config_file}") try: @@ -466,6 +478,9 @@ class SerenaAgent: serena_config: SerenaConfigBase | None = None, context: SerenaAgentContext | None = None, modes: list[SerenaAgentMode] | None = None, + enable_web_dashboard: bool | None = None, + enable_gui_log_window: bool | None = None, + gui_log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = None, ): """ :param project: the project to load immediately or None to not load any project; may be a path to the project or a name of @@ -476,9 +491,21 @@ class SerenaAgent: :param modes: list of modes in which the agent is operating (they will be combined), None for default modes. The modes may adjust prompts, tool availability, and tool descriptions. :param serena_config: the Serena configuration or None to read the configuration from the default location. + :param enable_web_dashboard: Whether to enable the web dashboard. If not specified, will take the value from the serena configuration. + :param enable_gui_log_window: Whether to enable the GUI log window. It currently does not work on macOS, and setting this to True will be ignored then. + If not specified, will take the value from the serena configuration. + :param gui_log_level: Log level for the GUI log window. If not specified, will take the value from the serena configuration. """ # obtain serena configuration self.serena_config = serena_config or SerenaConfig.from_config_file() + if enable_web_dashboard is not None: + self.serena_config.web_dashboard = enable_web_dashboard + if enable_gui_log_window is not None: + self.serena_config.gui_log_window_enabled = enable_gui_log_window + if gui_log_level is not None: + gui_log_level = cast(Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], gui_log_level.upper()) + # transform to int + self.serena_config.gui_log_window_level = logging.getLevelNamesMapping()[gui_log_level] # open GUI log window if enabled self._gui_log_handler: Union["GuiLogViewerHandler", None] = None # noqa @@ -706,13 +733,13 @@ class SerenaAgent: # Active modes active_mode_names = [mode.name for mode in self.get_active_modes()] - result_str += "Active modes: {}\n".format(", ".join(active_mode_names)) + result_str += "Active modes: {}\n".format(", ".join(active_mode_names)) + "\n" # Available but not active modes all_available_modes = SerenaAgentMode.list_registered_mode_names() inactive_modes = [mode for mode in all_available_modes if mode not in active_mode_names] if inactive_modes: - result_str += "Available but not active modes: {}\n".format(", ".join(inactive_modes)) + result_str += "Available but not active modes: {}\n".format(", ".join(inactive_modes)) + "\n" # Active tools result_str += "Active tools (after all exclusions from the project, context, and modes):\n" @@ -1914,6 +1941,8 @@ 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! + The only exception is when a user asks you to activate a project, in which case you should call the `activate_project` first + instead and then call this tool. """ return self.agent.create_system_prompt() diff --git a/src/serena/agno.py b/src/serena/agno.py index f6684eca..c9150693 100644 --- a/src/serena/agno.py +++ b/src/serena/agno.py @@ -14,9 +14,9 @@ from agno.tools.toolkit import Toolkit from dotenv import load_dotenv from sensai.util.logging import LogTime -from serena import serena_root_path from serena.agent import SerenaAgent, Tool, show_fatal_exception_safe from serena.config import SerenaAgentContext +from serena.constants import REPO_ROOT log = logging.getLogger(__name__) @@ -65,7 +65,7 @@ class SerenaAgnoAgentProvider: return cls._agent # change to Serena root - os.chdir(serena_root_path()) + os.chdir(REPO_ROOT) load_dotenv() @@ -94,7 +94,7 @@ class SerenaAgnoAgentProvider: # If project file path is relative, make it absolute by joining with project root if not project_file.is_absolute(): # Get the project root directory (parent of scripts directory) - project_root = Path(serena_root_path()) + project_root = Path(REPO_ROOT) project_file = project_root / args_project_file # Ensure the path is normalized and absolute diff --git a/src/serena/config.py b/src/serena/config.py index 57b7a686..0b9a85de 100644 --- a/src/serena/config.py +++ b/src/serena/config.py @@ -121,7 +121,13 @@ class SerenaAgentContext: try: return cls.from_name(str(name_or_path)) except FileNotFoundError: - return cls.from_yaml(name_or_path) + try: + return cls.from_yaml(name_or_path) + except FileNotFoundError as e: + raise FileNotFoundError( + f"Context {name_or_path} not found in {CONTEXT_YAMLS_DIR}. You can load a custom context by using from_yaml() instead.\n" + f"Available contexts:\n{cls.list_registered_context_names()}" + ) from e @classmethod def list_registered_context_names(cls) -> list[str]: diff --git a/src/serena/constants.py b/src/serena/constants.py index 5b138e90..9e0980fe 100644 --- a/src/serena/constants.py +++ b/src/serena/constants.py @@ -1,15 +1,19 @@ from pathlib import Path _repo_root_path = Path(__file__).parent.parent.parent.resolve() +_serena_pkg_path = Path(__file__).parent.resolve() REPO_ROOT = str(_repo_root_path) -PROMPT_TEMPLATES_DIR = str(_repo_root_path / "config" / "prompt_templates") -CONTEXT_YAMLS_DIR = str(_repo_root_path / "config" / "contexts") -MODE_YAMLS_DIR = str(_repo_root_path / "config" / "modes") +PROMPT_TEMPLATES_DIR = str(_serena_pkg_path / "resources" / "config" / "prompt_templates") +CONTEXT_YAMLS_DIR = str(_serena_pkg_path / "resources" / "config" / "contexts") +MODE_YAMLS_DIR = str(_serena_pkg_path / "resources" / "config" / "modes") +SERENA_DASHBOARD_DIR = str(_serena_pkg_path / "resources" / "dashboard") +SERENA_ICON_DIR = str(_serena_pkg_path / "resources" / "icons") SERENA_MANAGED_DIR_NAME = ".serena" DEFAULT_CONTEXT = "desktop-app" DEFAULT_MODES = ("interactive", "editing") -PROJECT_TEMPLATE_FILE = str(_repo_root_path / "project.template.yml") +PROJECT_TEMPLATE_FILE = str(_serena_pkg_path / "resources" / "project.template.yml") +SELENA_CONFIG_TEMPLATE_FILE = str(_serena_pkg_path / "resources" / "serena_config.template.yml") diff --git a/src/serena/dashboard.py b/src/serena/dashboard.py index d52040b5..4b0419ac 100644 --- a/src/serena/dashboard.py +++ b/src/serena/dashboard.py @@ -10,7 +10,7 @@ from fastapi.staticfiles import StaticFiles from pydantic import BaseModel from sensai.util import logging -from serena import serena_root_path +from serena.constants import SERENA_DASHBOARD_DIR log = logging.getLogger(__name__) @@ -75,8 +75,7 @@ class SerenaDashboardAPI: self._setup_routes() def _setup_routes(self) -> None: - static_dir = os.path.join(serena_root_path(), "dashboard") - self._app.mount("/dashboard", StaticFiles(directory=static_dir), name="dashboard") + self._app.mount("/dashboard", StaticFiles(directory=SERENA_DASHBOARD_DIR), name="dashboard") self._app.add_api_route("/get_log_messages", self._get_log_messages, methods=["POST"], response_model=ResponseLog) self._app.add_api_route("/get_tool_names", self._get_tool_names, methods=["GET"], response_model=ResponseToolNames) diff --git a/src/serena/mcp.py b/src/serena/mcp.py index a8c21911..b30d1984 100644 --- a/src/serena/mcp.py +++ b/src/serena/mcp.py @@ -102,6 +102,9 @@ def create_mcp_server_and_agent( port: int = 8000, context: str = DEFAULT_CONTEXT, modes: Sequence[str] = DEFAULT_MODES, + enable_web_dashboard: bool | None = None, + enable_gui_log_window: bool | None = None, + gui_log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = None, ) -> tuple[FastMCP, SerenaAgent]: """ Create an MCP server. @@ -113,6 +116,10 @@ def create_mcp_server_and_agent( :param port: The port to bind to :param context: The context name or path to context file :param modes: List of mode names or paths to mode files + :param enable_web_dashboard: Whether to enable the web dashboard. If not specified, will take the value from the serena configuration. + :param enable_gui_log_window: Whether to enable the GUI log window. It currently does not work on macOS, and setting this to True will be ignored then. + If not specified, will take the value from the serena configuration. + :param gui_log_level: Log level for the GUI log window. If not specified, will take the value from the serena configuration. """ mcp: FastMCP | None = None context_instance = SerenaAgentContext.load(context) @@ -125,6 +132,9 @@ def create_mcp_server_and_agent( # project_activation_callback=update_tools context=context_instance, modes=modes_instances, + enable_web_dashboard=enable_web_dashboard, + enable_gui_log_window=enable_gui_log_window, + gui_log_level=gui_log_level, ) except Exception as e: show_fatal_exception_safe(e) @@ -237,6 +247,27 @@ PROJECT_TYPE = ProjectType() default=8000, help="Port to bind to (for SSE transport).", ) +@click.option( + "--enable-web-dashboard", + type=bool, + is_flag=False, + default=None, + help="Whether to enable the web dashboard. If not specified, will take the value from the serena configuration.", +) +@click.option( + "--enable-gui-log-window", + type=bool, + is_flag=False, + default=None, + help="Whether to enable the GUI log window. It currently does not work on macOS, and setting this to True will be ignored then. " + "If not specified, will take the value from the serena configuration.", +) +@click.option( + "--gui-log-level", + type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]), + default=None, + help="Log level for the GUI log window. If not specified, will take the value from the serena configuration.", +) def start_mcp_server( project_file_opt: str | None, project_file_arg: str | None, @@ -245,6 +276,9 @@ def start_mcp_server( transport: Literal["stdio", "sse"] = "stdio", host: str = "0.0.0.0", port: int = 8000, + enable_web_dashboard: bool | None = None, + enable_gui_log_window: bool | None = None, + gui_log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = None, ) -> None: """Starts the Serena MCP server. By default, will not activate any project at startup. If you want to start with an already active project, use --project to pass the project name or path. @@ -256,7 +290,16 @@ def start_mcp_server( # This is for backward compatibility with the old CLI, should be removed in the future! project_file = project_file_arg if project_file_arg is not None else project_file_opt - mcp_server, agent = create_mcp_server_and_agent(project=project_file, host=host, port=port, context=context, modes=modes) + mcp_server, agent = create_mcp_server_and_agent( + project=project_file, + host=host, + port=port, + context=context, + modes=modes, + enable_web_dashboard=enable_web_dashboard, + enable_gui_log_window=enable_gui_log_window, + gui_log_level=gui_log_level, + ) # log after server creation such that the log appears in the GUI if project_file_arg is not None: diff --git a/config/contexts/agent.yml b/src/serena/resources/config/contexts/agent.yml similarity index 100% rename from config/contexts/agent.yml rename to src/serena/resources/config/contexts/agent.yml diff --git a/config/contexts/desktop-app.yml b/src/serena/resources/config/contexts/desktop-app.yml similarity index 100% rename from config/contexts/desktop-app.yml rename to src/serena/resources/config/contexts/desktop-app.yml diff --git a/config/contexts/ide-assistant.yml b/src/serena/resources/config/contexts/ide-assistant.yml similarity index 100% rename from config/contexts/ide-assistant.yml rename to src/serena/resources/config/contexts/ide-assistant.yml diff --git a/config/modes/editing.yml b/src/serena/resources/config/modes/editing.yml similarity index 95% rename from config/modes/editing.yml rename to src/serena/resources/config/modes/editing.yml index 431fe55b..901f32e8 100644 --- a/config/modes/editing.yml +++ b/src/serena/resources/config/modes/editing.yml @@ -16,7 +16,7 @@ prompt: | 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 alread know that you need to read the body of the constructor of the class Foo, you can directly + 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`. @@ -37,12 +37,13 @@ prompt: | then use your knowledge of the codebase to write the regex, if you haven't collected enough information of this content yet. You are extremely good at regex, so you never need to check whether the replacement produced the correct result. In particular, you know what to escape and what not to escape, and you know how to use wildcards. + Also, the regex tool never adds any indentation (contrary to the symbolic editing tools), so you have to take care to add the correct indentation + when using it to insert code. Moreover, the replacement tool will fail if it can't perform the desired replacement, and this is all the feedback you need. Your overall goal for replacement operations is to use relatively short regexes, since I want you to minimize the number of output tokens. For replacements of larger chunks of code, this means you intelligently make use of wildcards for the middle part and of characteristic snippets for the before/after parts that uniquely identify the chunk. - For small replacements, up to a single line, you follow the following rules: 1. If the snippet to be replaced is likely to be unique within the file, you perform the replacement by directly using the escaped version of the diff --git a/config/modes/interactive.yml b/src/serena/resources/config/modes/interactive.yml similarity index 100% rename from config/modes/interactive.yml rename to src/serena/resources/config/modes/interactive.yml diff --git a/config/modes/no-onboarding.yml b/src/serena/resources/config/modes/no-onboarding.yml similarity index 100% rename from config/modes/no-onboarding.yml rename to src/serena/resources/config/modes/no-onboarding.yml diff --git a/config/modes/onboarding.yml b/src/serena/resources/config/modes/onboarding.yml similarity index 100% rename from config/modes/onboarding.yml rename to src/serena/resources/config/modes/onboarding.yml diff --git a/config/modes/one-shot.yml b/src/serena/resources/config/modes/one-shot.yml similarity index 100% rename from config/modes/one-shot.yml rename to src/serena/resources/config/modes/one-shot.yml diff --git a/config/modes/planning.yml b/src/serena/resources/config/modes/planning.yml similarity index 52% rename from config/modes/planning.yml rename to src/serena/resources/config/modes/planning.yml index 53e2989b..c76501e8 100644 --- a/config/modes/planning.yml +++ b/src/serena/resources/config/modes/planning.yml @@ -8,7 +8,19 @@ prompt: | 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 and search_for_pattern if you need to. + 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. @@ -21,3 +33,4 @@ excluded_tools: - replace_lines - insert_at_line - execute_shell_command + - replace_regex diff --git a/config/prompt_templates/simple_tool_outputs.yml b/src/serena/resources/config/prompt_templates/simple_tool_outputs.yml similarity index 100% rename from config/prompt_templates/simple_tool_outputs.yml rename to src/serena/resources/config/prompt_templates/simple_tool_outputs.yml diff --git a/config/prompt_templates/system_prompt.yml b/src/serena/resources/config/prompt_templates/system_prompt.yml similarity index 100% rename from config/prompt_templates/system_prompt.yml rename to src/serena/resources/config/prompt_templates/system_prompt.yml diff --git a/dashboard/dashboard.js b/src/serena/resources/dashboard/dashboard.js similarity index 100% rename from dashboard/dashboard.js rename to src/serena/resources/dashboard/dashboard.js diff --git a/dashboard/index.html b/src/serena/resources/dashboard/index.html similarity index 100% rename from dashboard/index.html rename to src/serena/resources/dashboard/index.html diff --git a/dashboard/jquery.min.js b/src/serena/resources/dashboard/jquery.min.js similarity index 100% rename from dashboard/jquery.min.js rename to src/serena/resources/dashboard/jquery.min.js diff --git a/dashboard/serena-icon-16.png b/src/serena/resources/dashboard/serena-icon-16.png similarity index 100% rename from dashboard/serena-icon-16.png rename to src/serena/resources/dashboard/serena-icon-16.png diff --git a/dashboard/serena-icon-32.png b/src/serena/resources/dashboard/serena-icon-32.png similarity index 100% rename from dashboard/serena-icon-32.png rename to src/serena/resources/dashboard/serena-icon-32.png diff --git a/dashboard/serena-icon-48.png b/src/serena/resources/dashboard/serena-icon-48.png similarity index 100% rename from dashboard/serena-icon-48.png rename to src/serena/resources/dashboard/serena-icon-48.png diff --git a/dashboard/serena-logs.png b/src/serena/resources/dashboard/serena-logs.png similarity index 100% rename from dashboard/serena-logs.png rename to src/serena/resources/dashboard/serena-logs.png diff --git a/project.template.yml b/src/serena/resources/project.template.yml similarity index 100% rename from project.template.yml rename to src/serena/resources/project.template.yml diff --git a/serena_config.template.yml b/src/serena/resources/serena_config.template.yml similarity index 100% rename from serena_config.template.yml rename to src/serena/resources/serena_config.template.yml diff --git a/test/serena/__snapshots__/test_symbol_editing.ambr b/test/serena/__snapshots__/test_symbol_editing.ambr index 4fa7309d..2b698a22 100644 --- a/test/serena/__snapshots__/test_symbol_editing.ambr +++ b/test/serena/__snapshots__/test_symbol_editing.ambr @@ -629,7 +629,7 @@ # Instance variable with type annotation self.typed_instance_var: list[str] = ["item1", "item2"] - + def modify_instance_var(self): # This body has been replaced self.instance_var = "Replaced!" @@ -694,7 +694,7 @@ constructor(value: number) { this.value = value; } - + function printValue() { // This body has been replaced console.warn("New value: " + this.value); diff --git a/uv.lock b/uv.lock index c098ce28..8be9884e 100644 --- a/uv.lock +++ b/uv.lock @@ -970,7 +970,6 @@ name = "serena" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "agno" }, { name = "docstring-parser" }, { name = "dotenv" }, { name = "fastapi" }, @@ -1016,7 +1015,6 @@ google = [ [package.metadata] requires-dist = [ - { name = "agno", specifier = ">=1.2.15" }, { name = "agno", marker = "extra == 'agno'", specifier = ">=1.2.6" }, { name = "anthropic", marker = "extra == 'anthropic'", specifier = ">=0.49.0" }, { name = "black", extras = ["jupyter"], marker = "extra == 'dev'", specifier = ">=23.7.0" },