diff --git a/scripts/agno_agent.py b/scripts/agno_agent.py index 612ad1ea..19e94d59 100644 --- a/scripts/agno_agent.py +++ b/scripts/agno_agent.py @@ -1,7 +1,8 @@ +import argparse import os from logging import Logger +from pathlib import Path -import click from agno.agent.agent import Agent from agno.memory.agent import AgentMemory from agno.models.anthropic.claude import Claude @@ -10,7 +11,6 @@ from agno.playground.playground import Playground from agno.playground.serve import serve_playground_app from agno.storage.sqlite import SqliteStorage from dotenv import load_dotenv -from fastapi import FastAPI from sensai.util import logging from sensai.util.helper import mark_used @@ -19,57 +19,64 @@ from serena.agno import SerenaAgnoToolkit mark_used(Gemini, Claude) -os.chdir(os.path.dirname(os.path.abspath(__file__))) +os.chdir(Path(__file__).parent) Logger.root.setLevel(logging.INFO) load_dotenv() -# The app object must be in the module scope so that the server can access it for hot reloading -app: FastAPI | None = None + +parser = argparse.ArgumentParser(description="Serena coding assistant") +parser.add_argument("--project-file", required=True, help="Path to the project file, either absolute or relative to the root directory") +args = parser.parse_args() + +project_file = Path(args.project_file).resolve() +# 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(__file__).parent.parent + project_file = project_root / args.project_file + +# Ensure the path is normalized and absolute +project_file = project_file.resolve() -@click.command() -@click.option("--project-file", default="../myproject.yml", help="Path to the project configuration YAML file") -def main(project_file): - global app # noqa: PLW0603 - serena_agent = SerenaAgent(project_file, start_language_server=True) +serena_agent = SerenaAgent(str(project_file), start_language_server=True) - # Even though we don't want to keep history between sessions, - # for the agno ui to work as a conversation, we a persistent storage on disk - # This storage should be deleted between sessions. - # Note that this might collide with custom options for the agent, like adding vector-search based tools. - # See here for an explanation: https://www.reddit.com/r/agno/comments/1jk6qea/regarding_the_built_in_memory/ - sql_db_path = os.path.join("tmp", "agent_storage.db") - os.makedirs(os.path.dirname(sql_db_path), exist_ok=True) - # delete the db file if it exists - if os.path.exists(sql_db_path): - os.remove(sql_db_path) +# Even though we don't want to keep history between sessions, +# for the agno ui to work as a conversation, we a persistent storage on disk +# This storage should be deleted between sessions. +# Note that this might collide with custom options for the agent, like adding vector-search based tools. +# See here for an explanation: https://www.reddit.com/r/agno/comments/1jk6qea/regarding_the_built_in_memory/ +sql_db_path = Path("tmp") / "agent_storage.db" +sql_db_path.parent.mkdir(exist_ok=True) +# delete the db file if it exists +if sql_db_path.exists(): + sql_db_path.unlink() - model = Claude(id="claude-3-7-sonnet-20250219") - # Or use any other model supported by agno, e.g. the newest Gemini: - # model = Gemini(id="gemini-2.5-pro-exp-03-25") +# model = Claude(id="claude-3-7-sonnet-20250219") +# Or use any other model supported by agno, e.g. the newest Gemini: +model = Gemini(id="gemini-2.5-pro-exp-03-25") - agno_agent = Agent( - name="Serena", - model=model, - # See explanation above on why storage is needed - storage=SqliteStorage(table_name="serena_agent_sessions", db_file=sql_db_path), - description="A fully-featured coding assistant", - tools=[SerenaAgnoToolkit(serena_agent)], # type: ignore - # The tool calls will be shown in the UI anyway since whether to show them is configurable per tool - # To see detailed logs, you should use the serena logger (configure it in the project file path) - show_tool_calls=False, - markdown=True, - system_message=serena_agent.prompt_factory.create_system_prompt(), - telemetry=False, - memory=AgentMemory(), - add_history_to_messages=True, - num_history_responses=100, # you might want to adjust this (expense vs. history awareness) - ) +agno_agent = Agent( + name="Serena", + model=model, + # See explanation above on why storage is needed + storage=SqliteStorage(table_name="serena_agent_sessions", db_file=str(sql_db_path)), + description="A fully-featured coding assistant", + tools=[SerenaAgnoToolkit(serena_agent)], # type: ignore + # The tool calls will be shown in the UI anyway since whether to show them is configurable per tool + # To see detailed logs, you should use the serena logger (configure it in the project file path) + show_tool_calls=False, + markdown=True, + system_message=serena_agent.prompt_factory.create_system_prompt(), + telemetry=False, + memory=AgentMemory(), + add_history_to_messages=True, + num_history_responses=100, # you might want to adjust this (expense vs. history awareness) +) - app = Playground(agents=[agno_agent]).get_app() - serve_playground_app("agno_agent:app", reload=False) +app = Playground(agents=[agno_agent]).get_app() if __name__ == "__main__": - main() + serve_playground_app("agno_agent:app", reload=False) diff --git a/src/serena/agent.py b/src/serena/agent.py index cd60dd5f..66dba0fb 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -501,7 +501,7 @@ class FindReferencingSymbolsTool(Tool): :param include_body: whether to include the body of the symbols in the result. Note that this might lead to a very long output, so you should only use this if you actually need the body of the referencing symbols for the task at hand. Usually it is a better idea to find - the referencing symbols without the body and then use the find_symbol tool to get the body of + the referencing symbols without the body and then use the find_symbol tool to get the body of specific symbols if needed. :param include_kinds: an optional list of integers representing the LSP symbol kinds to include. If provided, only symbols of the given kinds will be included in the result.