diff --git a/.gitignore b/.gitignore index 2235c91..1c1823b 100644 --- a/.gitignore +++ b/.gitignore @@ -139,7 +139,7 @@ pylint.html # Serena-specific /*.yml !myproject.demo.yml - +/agent-ui # Cache is in .multilspy **/.multilspy/** \ No newline at end of file diff --git a/scripts/agno_agent.py b/scripts/agno_agent.py index 020e415..d5b3017 100644 --- a/scripts/agno_agent.py +++ b/scripts/agno_agent.py @@ -1,17 +1,12 @@ -from agno.agent import Agent from agno.models.google import Gemini from agno.playground import Playground, serve_playground_app -serena_agent = Agent( - model=Gemini(id="gemini-2.5-pro-exp-03-25"), - description="Serena", - tools=[], # Add serena tools here - show_tool_calls=True, - markdown=True, - system_message="", # use PromptFactory -) +from serena.agno import create_agno_agent -app = Playground(agents=[serena_agent]).get_app() - -if __name__ == "main": - serve_playground_app("playground:app", reload=True) +if __name__ == "__main__": + serena_agent = create_agno_agent( + project_file_path="myproject.yml", + model=Gemini(id="gemini-2.5-pro-exp-03-25"), + ) + app = Playground(agents=[serena_agent]).get_app() + serve_playground_app(app, reload=False) diff --git a/src/serena/agent.py b/src/serena/agent.py index a6e44c7..62a72ef 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -10,7 +10,7 @@ import sys import traceback from abc import ABC from collections import defaultdict -from collections.abc import Iterator, Sequence +from collections.abc import Callable, Iterator, Sequence from contextlib import contextmanager from logging import Logger from pathlib import Path @@ -146,6 +146,19 @@ class Tool(Component): name = "".join(["_" + c.lower() if c.isupper() else c for c in name]).lstrip("_") return name + def get_apply_fn(self) -> Callable: + apply_fn = getattr(self, "apply") + if apply_fn is None: + raise Exception(f"{self} does not define method apply") + return apply_fn + + def get_description(self) -> str: + apply_fn = self.get_apply_fn() + docstring = apply_fn.__doc__ + if docstring is None: + raise Exception(f"Missing docstring for {self}") + return docstring + @staticmethod def _log_tool_application(frame: Any) -> None: params = {} @@ -168,7 +181,7 @@ class Tool(Component): ) return result - def apply_ex(self, *args, log_call: bool = True, catch_exceptions: bool = True, **kwargs) -> str: + def apply_ex(self, *args, log_call: bool = True, catch_exceptions: bool = True, **kwargs) -> str: # type: ignore """ Applies the tool with the given arguments """ diff --git a/src/serena/agno.py b/src/serena/agno.py new file mode 100644 index 0000000..1daa2be --- /dev/null +++ b/src/serena/agno.py @@ -0,0 +1,32 @@ +from agno.agent import Agent +from agno.models.base import Model +from agno.tools import Function + +from serena.agent import SerenaAgent + + +def create_agno_agent( + project_file_path: str, model: Model, system_prompt: str = "", markdown: bool = True, show_tool_calls: bool = True +) -> Agent: + serena_agent = SerenaAgent(project_file_path) + tools: list[Function] = [] + for tool in serena_agent.tools.values(): + + def entrypoint(*args, tool=tool, **kwargs): # type: ignore + tool.apply_ex(*args, log_call=True, catch_exceptions=True, **kwargs) + + function = Function.from_callable(tool.get_apply_fn()) + function.name = tool.get_name() + function.entrypoint = entrypoint + tools.append(function) + + agno_agent = Agent( + model=model, + description="Serena", + tools=tools, # type: ignore + show_tool_calls=show_tool_calls, + markdown=markdown, + system_message=system_prompt, + ) + + return agno_agent