diff --git a/python/composio/cli/apps.py b/python/composio/cli/apps.py index e85ed7ada11..209d39e85c1 100755 --- a/python/composio/cli/apps.py +++ b/python/composio/cli/apps.py @@ -249,13 +249,7 @@ def _update_triggers( ) for app in apps: for trigger in [trigger for trigger in triggers if trigger.appKey == app.key]: - trigger_names.append( - ( - _get_enum_key(name=app.key) - + "_" - + _get_enum_key(name=trigger.display_name) - ).upper() - ) + trigger_names.append(_get_enum_key(name=trigger.name).upper()) enums.base.TriggerData( name=trigger.name, app=app.key, diff --git a/python/composio/client/collections.py b/python/composio/client/collections.py index 55fcb3c2ae6..82fc0dc69ea 100644 --- a/python/composio/client/collections.py +++ b/python/composio/client/collections.py @@ -10,6 +10,7 @@ import typing as t import warnings from concurrent.futures import Future, ThreadPoolExecutor +from unittest import mock import pysher import typing_extensions as te @@ -624,6 +625,8 @@ def connect(self, timeout: float = 15.0) -> TriggerSubscription: "x-api-key": self.api_key, }, ) + # Patch pusher logger + pusher.connection.logger = mock.MagicMock() # type: ignore pusher.connection.bind( "pusher:connection_established", self._get_connection_handler( diff --git a/python/composio/client/enums/_trigger.py b/python/composio/client/enums/_trigger.py index feced958659..7c801b6eb99 100644 --- a/python/composio/client/enums/_trigger.py +++ b/python/composio/client/enums/_trigger.py @@ -15,24 +15,24 @@ class Trigger(_AnnotatedEnum[TriggerData], path=TRIGGERS_CACHE): GITHUB_STAR_ADDED_EVENT: "Trigger" GMAIL_NEW_GMAIL_MESSAGE: "Trigger" GOOGLEDRIVE_GOOGLE_DRIVE_CHANGES: "Trigger" - NOTION_NEW_PAGE: "Trigger" - SLACK_NEW_CHANNEL_CREATED: "Trigger" + NOTION_PAGE_ADDED_TO_DATABASE: "Trigger" + SLACK_CHANNEL_CREATED: "Trigger" SLACK_REACTION_ADDED: "Trigger" SLACK_REACTION_REMOVED: "Trigger" - SLACK_NEW_MESSAGE: "Trigger" - SLACK_THREAD_REPLY: "Trigger" - SLACKBOT_NEW_CHANNEL_CREATED: "Trigger" + SLACK_RECEIVE_MESSAGE: "Trigger" + SLACK_RECEIVE_THREAD_REPLY: "Trigger" + SLACKBOT_CHANNEL_CREATED: "Trigger" SLACKBOT_REACTION_ADDED: "Trigger" SLACKBOT_REACTION_REMOVED: "Trigger" - SLACKBOT_NEW_MESSAGE: "Trigger" - SLACKBOT_THREAD_REPLY: "Trigger" - SPOTIFY_NEW_DEVICE_ADDED: "Trigger" - SPOTIFY_NEW_SONG_ADDED_TO_PLAYLIST: "Trigger" - SPOTIFY_NEW_PLAYLIST_CREATED_OR_DELETED: "Trigger" - YOUTUBE_NEW_YOUTUBE_ACTIVITY: "Trigger" - YOUTUBE_NEW_ITEM_IN_YOUTUBE_PLAYLIST: "Trigger" - YOUTUBE_NEW_PLAYLIST_IN_YOUTUBE_CHANNEL: "Trigger" - YOUTUBE_NEW_YOUTUBE_CHANNEL_SUBSCRIPTION: "Trigger" + SLACKBOT_RECEIVE_MESSAGE: "Trigger" + SLACKBOT_RECEIVE_THREAD_REPLY: "Trigger" + SPOTIFY_NEW_DEVICE_TRIGGER: "Trigger" + SPOTIFY_PLAYLIST_ITEM_TRIGGER: "Trigger" + SPOTIFY_PLAYLIST_TRIGGER: "Trigger" + YOUTUBE_NEW_ACTIVITY_TRIGGER: "Trigger" + YOUTUBE_NEW_ITEM_IN_PLAYLIST_TRIGGER: "Trigger" + YOUTUBE_NEW_PLAYLIST_TRIGGER: "Trigger" + YOUTUBE_NEW_SUBSCRIPTION_TRIGGER: "Trigger" @property def name(self) -> str: diff --git a/python/composio/tools/__init__.py b/python/composio/tools/__init__.py index 430e52c167e..dd48d766691 100644 --- a/python/composio/tools/__init__.py +++ b/python/composio/tools/__init__.py @@ -13,11 +13,12 @@ from composio.client import Composio from composio.client.collections import ( ActionModel, + ConnectedAccountModel, FileModel, SuccessExecuteActionResponseModel, TriggerSubscription, ) -from composio.client.enums import Action, ActionType, App, AppType, Tag, TagType +from composio.client.enums import Action, ActionType, App, AppType, TagType from composio.client.exceptions import ComposioClientError from composio.client.local_handler import LocalToolHandler from composio.constants import ( @@ -27,7 +28,7 @@ LOCAL_OUTPUT_FILE_DIRECTORY_NAME, USER_DATA_FILE_NAME, ) -from composio.exceptions import raise_api_key_missing +from composio.exceptions import ComposioSDKError, raise_api_key_missing from composio.storage.user import UserData @@ -35,6 +36,7 @@ class ComposioToolSet: """Composio toolset.""" _remote_client: Composio + _connected_accounts: t.Optional[t.List[ConnectedAccountModel]] = None def __init__( self, @@ -86,6 +88,26 @@ def client(self) -> Composio: def runtime(self) -> t.Optional[str]: return self._runtime + def check_connected_account(self, action: ActionType) -> None: + """Check if connected account is required and if required it exists or not.""" + action = Action(action) + if action.no_auth: + return + + if self._connected_accounts is None: + self._connected_accounts = t.cast( + t.List[ConnectedAccountModel], + self.client.connected_accounts.get(), + ) + + if action.app not in [ + connection.appUniqueId for connection in self._connected_accounts + ]: + raise ComposioSDKError( + f"No connected account found for app `{action.app}`; " + f"Run `composio add {action.app}` to fix this" + ) + def execute_action( self, action: t.Union[Action, str], @@ -102,12 +124,14 @@ def execute_action( Any: The output of the action execution. :return: Output object from the function call. """ - if isinstance(action, str): - action = Action(action) - + action = Action(action) if action.is_local: - return self._local_client.execute_action(action=action, request_data=params) + return self._local_client.execute_action( + action=action, + request_data=params, + ) + self.check_connected_account(action=action) output = self.client.get_entity( id=entity_id, ).execute( @@ -196,6 +220,8 @@ def get_action_schemas( ) items = items + remote_items + for item in items: + self.check_connected_account(action=item.name) return items def create_trigger_listener(self, timeout: float = 15.0) -> TriggerSubscription: diff --git a/python/plugins/autogen/setup.py b/python/plugins/autogen/setup.py index dbfe59068c3..13756b6eaa3 100644 --- a/python/plugins/autogen/setup.py +++ b/python/plugins/autogen/setup.py @@ -9,7 +9,7 @@ setup( name="composio_autogen", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your Autogen agent.", @@ -22,6 +22,6 @@ "Operating System :: OS Independent", ], python_requires=">=3.9,<4", - install_requires=["composio_core==0.3.15", "pyautogen>=0.2.19"], + install_requires=["composio_core==0.3.16", "pyautogen>=0.2.19"], include_package_data=True, ) diff --git a/python/plugins/claude/setup.py b/python/plugins/claude/setup.py index 59e2960d75b..e0022f125a0 100644 --- a/python/plugins/claude/setup.py +++ b/python/plugins/claude/setup.py @@ -9,7 +9,7 @@ setup( name="composio_claude", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your Claude LLMs.", @@ -22,6 +22,6 @@ "Operating System :: OS Independent", ], python_requires=">=3.9,<4", - install_requires=["composio_openai==0.3.15", "anthropic>=0.25.7"], + install_requires=["composio_openai==0.3.16", "anthropic>=0.25.7"], include_package_data=True, ) diff --git a/python/plugins/crew_ai/setup.py b/python/plugins/crew_ai/setup.py index d66a934444b..9b778a87144 100644 --- a/python/plugins/crew_ai/setup.py +++ b/python/plugins/crew_ai/setup.py @@ -9,7 +9,7 @@ setup( name="composio_crewai", - version="0.3.15", + version="0.3.16", author="Himanshu", author_email="himanshu@composio.dev", description="Use Composio to get an array of tools with your CrewAI agent.", @@ -22,6 +22,6 @@ "Operating System :: OS Independent", ], python_requires=">=3.9,<4", - install_requires=["composio_langchain==0.3.15"], + install_requires=["composio_langchain==0.3.16"], include_package_data=True, ) diff --git a/python/plugins/griptape/setup.py b/python/plugins/griptape/setup.py index 085215c5a89..c84218dda44 100644 --- a/python/plugins/griptape/setup.py +++ b/python/plugins/griptape/setup.py @@ -9,7 +9,7 @@ setup( name="composio_griptape", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your Griptape wokflow.", @@ -22,6 +22,6 @@ "Operating System :: OS Independent", ], python_requires=">=3.9,<4", - install_requires=["composio_core==0.3.15", "griptape>=0.24.2"], + install_requires=["composio_core==0.3.16", "griptape>=0.24.2"], include_package_data=True, ) diff --git a/python/plugins/julep/setup.py b/python/plugins/julep/setup.py index 73b1c57ed6c..7651651ae6f 100644 --- a/python/plugins/julep/setup.py +++ b/python/plugins/julep/setup.py @@ -9,7 +9,7 @@ setup( name="composio_julep", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your Julep wokflow.", @@ -22,6 +22,6 @@ "Operating System :: OS Independent", ], python_requires=">=3.9,<4", - install_requires=["composio_openai==0.3.15", "julep>=0.3.2"], + install_requires=["composio_openai==0.3.16", "julep>=0.3.2"], include_package_data=True, ) diff --git a/python/plugins/langchain/setup.py b/python/plugins/langchain/setup.py index 7d17e603e20..40ad7babf1a 100644 --- a/python/plugins/langchain/setup.py +++ b/python/plugins/langchain/setup.py @@ -9,7 +9,7 @@ setup( name="composio_langchain", - version="0.3.15", + version="0.3.16", author="Karan", author_email="karan@composio.dev", description="Use Composio to get an array of tools with your LangChain agent.", @@ -27,7 +27,7 @@ "langchain-openai>=0.0.2.post1", "pydantic>=2.6.4", "langchainhub>=0.1.15", - "composio_core==0.3.15", + "composio_core==0.3.16", ], include_package_data=True, ) diff --git a/python/plugins/llamaindex/setup.py b/python/plugins/llamaindex/setup.py index 939e66b44cf..4a14e3fe9fe 100644 --- a/python/plugins/llamaindex/setup.py +++ b/python/plugins/llamaindex/setup.py @@ -9,7 +9,7 @@ setup( name="composio_llamaindex", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your LlamaIndex agent.", @@ -24,7 +24,7 @@ python_requires=">=3.9,<4", install_requires=[ "llama_index>=0.10.43", - "composio_langchain==0.3.15", + "composio_langchain==0.3.16", ], include_package_data=True, ) diff --git a/python/plugins/lyzr/setup.py b/python/plugins/lyzr/setup.py index ddefeefbac3..a987d80b3f2 100644 --- a/python/plugins/lyzr/setup.py +++ b/python/plugins/lyzr/setup.py @@ -9,7 +9,7 @@ setup( name="composio_lyzr", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your Lyzr workflow.", @@ -25,7 +25,7 @@ install_requires=[ "lyzr-automata>=0.1.3", "pydantic>=2.6.4", - "composio_core==0.3.15", + "composio_core==0.3.16", "langchain>=0.1.0", ], include_package_data=True, diff --git a/python/plugins/openai/setup.py b/python/plugins/openai/setup.py index 66e0a542c7a..0e806b7038c 100644 --- a/python/plugins/openai/setup.py +++ b/python/plugins/openai/setup.py @@ -9,7 +9,7 @@ setup( name="composio_openai", - version="0.3.15", + version="0.3.16", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your OpenAI Function Call.", @@ -22,6 +22,6 @@ "Operating System :: OS Independent", ], python_requires=">=3.9,<4", - install_requires=["composio_core==0.3.15"], + install_requires=["composio_core==0.3.16"], include_package_data=True, ) diff --git a/python/setup.py b/python/setup.py index 6fdb4cbb189..e71a7accf63 100644 --- a/python/setup.py +++ b/python/setup.py @@ -10,7 +10,7 @@ setup( name="composio_core", - version="0.3.15", + version="0.3.16", author="Utkarsh", author_email="utkarsh@composio.dev", description="Core package to act as a bridge between composio platform and other services.", diff --git a/python/tests/test_client/test_collections.py b/python/tests/test_client/test_collections.py index 9350cf552aa..641f87f6af7 100644 --- a/python/tests/test_client/test_collections.py +++ b/python/tests/test_client/test_collections.py @@ -20,8 +20,8 @@ class TestTriggerNamesSerialization: def test_converts_trigger_objects_to_comma_separated_string(self): trigger_list = [ Trigger.GITHUB_COMMIT_EVENT, - Trigger.SLACK_NEW_MESSAGE, - Trigger.YOUTUBE_NEW_YOUTUBE_ACTIVITY, + Trigger.SLACK_RECEIVE_MESSAGE, + Trigger.YOUTUBE_NEW_ACTIVITY_TRIGGER, ] result = to_trigger_names(trigger_list) assert ( @@ -32,8 +32,8 @@ def test_converts_trigger_objects_to_comma_separated_string(self): def test_converts_trigger_strings_to_comma_separated_string(self): trigger_list = [ "github_commit_event", - "slack_new_message", - "youtube_new_youtube_activity", + "slack_receive_message", + "youtube_new_activity_trigger", ] result = to_trigger_names(trigger_list) assert ( @@ -44,8 +44,8 @@ def test_converts_trigger_strings_to_comma_separated_string(self): def test_converts_mix_of_trigger_objects_and_strings(self): trigger_list = [ Trigger.GITHUB_COMMIT_EVENT, - "slack_new_message", - Trigger.YOUTUBE_NEW_YOUTUBE_ACTIVITY, + "slack_receive_message", + Trigger.YOUTUBE_NEW_ACTIVITY_TRIGGER, ] result = to_trigger_names(trigger_list) assert ( diff --git a/python/tests/test_client/test_enum.py b/python/tests/test_client/test_enum.py index 372d999a8ed..55e0352fce4 100644 --- a/python/tests/test_client/test_enum.py +++ b/python/tests/test_client/test_enum.py @@ -29,7 +29,7 @@ def test_action_enum() -> None: def test_trigger_enum() -> None: """Test `Trigger` enum.""" - trigger = Trigger("slack_new_message") + trigger = Trigger("slack_receive_message") assert trigger.app == "slack" assert trigger.name == "slack_receive_message" diff --git a/python/tests/test_tools/test_toolset.py b/python/tests/test_tools/test_toolset.py index 6993ff3c672..55de50a1631 100644 --- a/python/tests/test_tools/test_toolset.py +++ b/python/tests/test_tools/test_toolset.py @@ -2,7 +2,10 @@ Test composio toolset. """ -from composio import App +import pytest + +from composio import Action, App +from composio.exceptions import ComposioSDKError from composio.tools import ComposioToolSet @@ -17,3 +20,15 @@ def test_find_actions_by_tags() -> None: ): assert "important" in action.tags assert action.app in ("github", "slack", "slackbot") + + +def test_uninitialize_app() -> None: + """Test if the usage of an app without connected account raises erorr or not.""" + with pytest.raises( + ComposioSDKError, + match=( + "No connected account found for app `apify`; " + "Run `composio add apify` to fix this" + ), + ): + ComposioToolSet().get_action_schemas(actions=[Action.APIFY_CREATE_APIFY_ACTOR])