From dfdf9faf471c5fbc4fa3db9f1878cd2322a7bc28 Mon Sep 17 00:00:00 2001 From: Karan Vaidya Date: Wed, 15 Jan 2025 00:45:29 +0530 Subject: [PATCH] Add autogen tools new version (#1190) --- python/composio/client/enums/action.pyi | 7 ++ python/composio/client/enums/app.pyi | 1 + python/composio/client/enums/tag.pyi | 2 + python/plugins/autogen/autogen_demo_2.py | 45 +++++++ .../autogen/composio_autogen/toolset.py | 113 +++++++++++++++++- python/plugins/autogen/setup.py | 2 + 6 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 python/plugins/autogen/autogen_demo_2.py diff --git a/python/composio/client/enums/action.pyi b/python/composio/client/enums/action.pyi index fd103d0e883..7a6f983ae38 100644 --- a/python/composio/client/enums/action.pyi +++ b/python/composio/client/enums/action.pyi @@ -1594,6 +1594,7 @@ class Action(Enum[ActionData], metaclass=EnumGenerator): CAL_GET_EVENT_TYPE_BY_TEAM_ID: "Action" CAL_GET_GOOGLE_CALENDAR_OAUTH_AUTHENTICATION_URL: "Action" CAL_GET_OAUTH_CLIENTS_USER: "Action" + CAL_GET_ORGANIZATION_ID: "Action" CAL_GET_ORGANIZATION_SCHEDULES: "Action" CAL_GET_ORGANIZATION_TEAMS_EVENT_TYPES: "Action" CAL_GET_ORGANIZATION_USER_SCHEDULES: "Action" @@ -1921,6 +1922,7 @@ class Action(Enum[ActionData], metaclass=EnumGenerator): CODE_ANALYSIS_TOOL_GET_METHOD_SIGNATURE: "Action" CODE_ANALYSIS_TOOL_GET_RELEVANT_CODE: "Action" CODE_FORMAT_TOOL_FORMAT_AND_LINT_CODEBASE: "Action" + COMPOSIO_ADVANCED_USE_CASE_SEARCH: "Action" COMPOSIO_CHECK_ACTIVE_CONNECTION: "Action" COMPOSIO_ENABLE_TRIGGER: "Action" COMPOSIO_EXECUTE_ACTION: "Action" @@ -8039,6 +8041,11 @@ class Action(Enum[ActionData], metaclass=EnumGenerator): TWITTER_USER_LOOKUP_BY_USERNAME: "Action" TWITTER_USER_LOOKUP_BY_USERNAMES: "Action" TWITTER_USER_LOOKUP_ME: "Action" + TYPEFULLY_CREATE_DRAFT: "Action" + TYPEFULLY_GET_NOTIFICATIONS: "Action" + TYPEFULLY_GET_RECENTLY_PUBLISHED: "Action" + TYPEFULLY_GET_RECENTLY_SCHEDULED: "Action" + TYPEFULLY_MARK_NOTIFICATIONS_READ: "Action" WEATHERMAP_WEATHER: "Action" WEBTOOL_SCRAPE_WEBSITE_CONTENT: "Action" WEBTOOL_SCRAPE_WEBSITE_ELEMENT: "Action" diff --git a/python/composio/client/enums/app.pyi b/python/composio/client/enums/app.pyi index 593a665a785..60450a3f2c4 100644 --- a/python/composio/client/enums/app.pyi +++ b/python/composio/client/enums/app.pyi @@ -261,6 +261,7 @@ class App(Enum[AppData], metaclass=EnumGenerator): TWITCH: "App" TWITTER: "App" TWITTER_MEDIA: "App" + TYPEFULLY: "App" VENLY: "App" VERO: "App" VISME: "App" diff --git a/python/composio/client/enums/tag.pyi b/python/composio/client/enums/tag.pyi index feef75d3766..652033192eb 100644 --- a/python/composio/client/enums/tag.pyi +++ b/python/composio/client/enums/tag.pyi @@ -1123,6 +1123,8 @@ class Tag(Enum[TagData], metaclass=EnumGenerator): TWITTER_TWEETS: "Tag" TWITTER_USAGE: "Tag" TWITTER_USERS: "Tag" + TYPEFULLY_DRAFTS: "Tag" + TYPEFULLY_NOTIFICATIONS: "Tag" WRIKE_ACCOUNTS: "Tag" WRIKE_CONTACTS: "Tag" WRIKE_CUSTOM_FIELDS: "Tag" diff --git a/python/plugins/autogen/autogen_demo_2.py b/python/plugins/autogen/autogen_demo_2.py new file mode 100644 index 00000000000..50c3d4d743c --- /dev/null +++ b/python/plugins/autogen/autogen_demo_2.py @@ -0,0 +1,45 @@ +""" +Autogen demo using get_tools() approach. +""" + +import asyncio +import os + +import dotenv +from autogen_agentchat.agents import AssistantAgent +from autogen_core import CancellationToken +from autogen_ext.models.openai import OpenAIChatCompletionClient + +from composio_autogen import App, ComposioToolSet + + +async def main(): + # Initialize toolset and get tools + composio_toolset = ComposioToolSet() + tools = composio_toolset.get_tools(apps=[App.GITHUB]) + + model_client = OpenAIChatCompletionClient( + model="gpt-4", + api_key=os.environ["OPENAI_API_KEY"], + ) + # Create assistant agent with tools + assistant = AssistantAgent( + name="github_assistant", + system_message=( + "You are an AI assistant that helps with GitHub tasks. " + "Use the provided tools to interact with GitHub." + ), + model_client=model_client, + tools=list(tools), + ) + + # Define task and initiate chat + task = "Star the repository composiohq/composio on GitHub" + result = await assistant.run(task=task, cancellation_token=CancellationToken()) + print(result) + + +if __name__ == "__main__": + # Load environment variables from .env + dotenv.load_dotenv() + asyncio.run(main()) diff --git a/python/plugins/autogen/composio_autogen/toolset.py b/python/plugins/autogen/composio_autogen/toolset.py index c7ddf2243f7..55c11bfe03d 100644 --- a/python/plugins/autogen/composio_autogen/toolset.py +++ b/python/plugins/autogen/composio_autogen/toolset.py @@ -6,9 +6,11 @@ import autogen import typing_extensions as te from autogen.agentchat.conversable_agent import ConversableAgent +from autogen_core.tools import FunctionTool from composio import Action, ActionType, AppType, TagType from composio.tools import ComposioToolSet as BaseComposioToolSet +from composio.tools.toolset import ProcessorsType from composio.utils.shared import get_signature_format_from_schema_params @@ -137,10 +139,14 @@ def execute_action(**kwargs: t.Any) -> t.Dict: ), closure=execute_action.__closure__, ) - function.__signature__ = Signature( # type: ignore - parameters=get_signature_format_from_schema_params( - schema_params=schema["parameters"], - ), + params = get_signature_format_from_schema_params( + schema_params=schema["parameters"], + ) + setattr(function, "__signature__", Signature(parameters=params)) + setattr( + function, + "__annotations__", + {p.name: p.annotation for p in params} | {"return": t.Dict[str, t.Any]}, ) function.__doc__ = ( description if description else f"Action {name} from {appName}" @@ -154,3 +160,102 @@ def execute_action(**kwargs: t.Any) -> t.Dict: ), description=description if description else f"Action {name} from {appName}", ) + + def _wrap_tool( + self, + schema: t.Dict[str, t.Any], + entity_id: t.Optional[str] = None, + ) -> FunctionTool: + """ + Wraps a composio action as an Autogen FunctionTool. + + Args: + schema: The action schema to wrap + entity_id: Optional entity ID for executing function calls + + Returns: + FunctionTool: Wrapped function as an Autogen FunctionTool + """ + name = schema["name"] + description = schema["description"] or f"Action {name} from {schema['appName']}" + + def execute_action(**kwargs: t.Any) -> t.Dict: + """Placeholder function for executing action.""" + return self.execute_action( + action=Action(value=name), + params=kwargs, + entity_id=entity_id or self.entity_id, + _check_requested_actions=True, + ) + + # Create function with proper signature + function = types.FunctionType( + code=execute_action.__code__, + globals=globals(), + name=self._process_function_name_for_registration(input_string=name), + closure=execute_action.__closure__, + ) + + # Set signature and annotations + params = get_signature_format_from_schema_params( + schema_params=schema["parameters"] + ) + setattr(function, "__signature__", Signature(parameters=params)) + setattr( + function, + "__annotations__", + {p.name: p.annotation for p in params} | {"return": t.Dict[str, t.Any]}, + ) + function.__doc__ = description + + return FunctionTool( + func=function, + description=description, + name=self._process_function_name_for_registration(input_string=name), + ) + + def get_tools( + self, + actions: t.Optional[t.Sequence[ActionType]] = None, + apps: t.Optional[t.Sequence[AppType]] = None, + tags: t.Optional[t.List[TagType]] = None, + entity_id: t.Optional[str] = None, + *, + processors: t.Optional[ProcessorsType] = None, + check_connected_accounts: bool = True, + ) -> t.Sequence[FunctionTool]: + """ + Get composio tools as Autogen FunctionTool objects. + + Args: + actions: List of actions to wrap + apps: List of apps to wrap + tags: Filter apps by given tags + entity_id: Entity ID for function wrapper + processors: Optional dict of processors to merge + check_connected_accounts: Whether to check for connected accounts + + Returns: + List of Autogen FunctionTool objects + """ + self.validate_tools(apps=apps, actions=actions, tags=tags) + if processors is not None: + self._merge_processors(processors) + + tools = [ + self._wrap_tool( + schema=tool.model_dump( + exclude_none=True, + ), + entity_id=entity_id or self.entity_id, + ) + for tool in self.get_action_schemas( + actions=actions, + apps=apps, + tags=tags, + check_connected_accounts=check_connected_accounts, + _populate_requested=True, + ) + ] + + return tools diff --git a/python/plugins/autogen/setup.py b/python/plugins/autogen/setup.py index be453caccf6..559486eb9a4 100644 --- a/python/plugins/autogen/setup.py +++ b/python/plugins/autogen/setup.py @@ -26,6 +26,8 @@ "composio_core>=0.6.11,<0.7.0", "pyautogen>=0.2.19", "flaml==2.2.0", + "autogen_core>=0.4.0", + "autogen_agentchat>=0.4.0", ], include_package_data=True, )