mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-14 02:16:21 +00:00
32 files changed
+153
-49
No files matched your search
@@ -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"
|
||||
@@ -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
|
||||
|
||||
|
||||
+1
-2
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
+38
-9
@@ -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()
|
||||
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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")
|
||||
@@ -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)
|
||||
|
||||
+44
-1
@@ -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:
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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);
|
||||
|
||||
@@ -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" },
|
||||
|
||||
Reference in new issue
Block a user