diff --git a/Makefile b/Makefile index 1fcba28410..a907074184 100644 --- a/Makefile +++ b/Makefile @@ -56,19 +56,19 @@ build: .PHONY: publish publish: dist - twine upload dist/* && \ + twine upload dist/* --username token --password "$$PYPI_PASSWORD" && \ for dir in plugins/*; do \ if [ -d "$$dir" ]; then \ - twine upload "$$dir"/dist/*; \ - fi \ + twine upload "$$dir"/dist/* --username token --password "$$PYPI_PASSWORD"; \ + fi; \ done .PHONY: test-publish test-publish: dist - twine upload --repository testpypi dist/* && \ + twine upload --repository testpypi dist/* --username token --password "$$PYPI_PASSWORD" && \ for dir in plugins/*; do \ if [ -d "$$dir" ]; then \ - twine upload --repository testpypi "$$dir"/dist/*; \ + twine upload --repository testpypi "$$dir"/dist/* --username token --password "$$PYPI_PASSWORD"; \ fi \ done diff --git a/Pipfile b/Pipfile index 6758bcce09..2092364d8b 100644 --- a/Pipfile +++ b/Pipfile @@ -27,4 +27,6 @@ crewai = "^0.28.8" pyautogen = "^0.2.26" langchain = "^0.1.16" lyzr = "^0.1.5" - +semver = "^3.0.2" +build = "^1.2.1" +setuptools = "^69.5.1" \ No newline at end of file diff --git a/composio/sdk/__init__.py b/composio/sdk/__init__.py index d713f8002d..9bef3c8bd9 100644 --- a/composio/sdk/__init__.py +++ b/composio/sdk/__init__.py @@ -1,11 +1,12 @@ from .core import ComposioCore, FrameworkEnum from .enums import Tag -from .sdk import Composio, SchemaFormat +from .sdk import Composio, SchemaFormat, format_schema __all__ = ( + "Tag", "Composio", "ComposioCore", - "Tag", + "format_schema", "FrameworkEnum", "SchemaFormat", "Tag", diff --git a/composio/sdk/core.py b/composio/sdk/core.py index 7815a4966b..14e00e8417 100644 --- a/composio/sdk/core.py +++ b/composio/sdk/core.py @@ -22,6 +22,9 @@ class FrameworkEnum(Enum): AUTOGEN = "autogen" LANGCHAIN = "langchain" LYZR = "lyzr" + CREWAI = "crewai" + JULEP = "julep" + OPENAI = "openai" __IS_FIRST_TIME__ = True diff --git a/composio/sdk/enums.py b/composio/sdk/enums.py index 210309513d..b89bf5445a 100644 --- a/composio/sdk/enums.py +++ b/composio/sdk/enums.py @@ -6,179 +6,206 @@ class Tag(Enum): class App(Enum): - ABLY = "ably" - ASANA = "asana" - ATLASSIAN = "atlassian" - BROWSEAI = "browseai" - CAL = "cal" - CONTENTFUL = "contentful" + MIRO = "miro" + JIRA = "jira" + TIMELY = "timely" + BOLDSIGN = "boldsign" STACK_EXCHANGE = "stack-exchange" - STRAVA = "strava" - AIRTABLE = "Airtable" - GOOGLEDOCS1 = "googledocs1" - GOOGLEDRIVE1 = "googledrive1" - GOOGLESHEETS1 = "googlesheets1" - GUSTO = "gusto" - ALCHEMY = "alchemy" - AMAZON = "amazon" - AMCARDS = "amcards" - AMPLITUDE = "amplitude" - AUTH0 = "auth0" - AXONAUT = "axonaut" - BAMBOOHR = "bamboohr" - BANNERBEAR = "bannerbear" - BATTLENET = "battlenet" - BITBUCKET = "bitbucket" - BITWARDEN = "bitwarden" - BOX = "box" - BRAINTREE = "braintree" - BRANDFETCH = "brandfetch" - BREVO = "brevo" - CALENDLY = "calendly" - CODEINTERPRETER = "codeinterpreter" - CUSTOMER_IO = "customer_io" - DATADOG = "datadog" - DATAGMA = "datagma" - EVENTBRITE = "eventbrite" - EXA = "exa" - EXIST = "exist" + GURU = "guru" FACEBOOK = "facebook" - FIGMA = "figma" - FILEMANAGER = "filemanager" - FITBIT = "fitbit" - FRESHBOOKS = "freshbooks" - FRESHDESK = "freshdesk" - FRONT = "front" - GCALENDAR = "gcalendar" + HACKERRANK_WORK = "hackerrank-work" + ADOBE = "adobe" + RING_CENTRAL = "ring-central" GITHUB = "github" GITLAB = "gitlab" - GMAIL = "gmail" - GOOGLE_DOCS = "google-docs" - GOOGLE_SHEETS = "google-sheets" - GORGIAS = "gorgias" - HACKERRANK_WORK = "hackerrank-work" - HARVEST = "harvest" + APIFY = "apify" + MAILCHIMP = "mailchimp" + BITBUCKET = "bitbucket" + SAGE = "sage" + TWITTER = "twitter" + GUMROAD = "gumroad" + YANDEX = "yandex" + STRAVA = "strava" + SURVEY_MONKEY = "survey-monkey" + TRELLO = "trello" + TWITCH = "twitch" + XERO = "xero" + BLACKBAUD = "blackbaud" + EPIC_GAMES = "epic-games" + GCALENDAR = "gcalendar" + FRONT = "front" + SLACKBOT = "slackbot" + YOUTUBE = "youtube" + PAGERDUTY = "pagerduty" + TASKADE = "taskade" + LINKHUT = "linkhut" HIGHLEVEL = "highlevel" + CLICKUP = "clickup" + GOOGLE_SHEETS = "google-sheets" HUBSPOT = "hubspot" - INTERCOM = "intercom" - JIRA = "jira" + SERPAPI = "serpapi" + DROPBOX = "dropbox" + SPLITWISE = "splitwise" + OKTA = "okta" + ABLY = "ably" + AERO_WORKFLOW = "aero-workflow" + BROWSERHUB = "browserhub" + BUBBLE = "bubble" + CAL = "cal" + CHATWORK = "chatwork" + CHMEETINGS = "chmeetings" + CONTENTFUL = "contentful" + CUSTOMER_IO = "customer_io" + DATADOG = "datadog" + DATAGMA = "datagma" + ATLASSIAN = "atlassian" + SNOWFLAKE = "snowflake" + TAPFORM = "tapform" + TEXTRAZOR = "textrazor" + TIMEKIT = "timekit" + MIXPANEL = "mixpanel" + DEMIO = "demio" + DIGICERT = "digicert" + PRINTNODE = "printnode" + PROCESS_STREET = "process-street" + RAVENSEOTOOLS = "ravenseotools" + MICROSOFT_TENANT = "microsoft-tenant" + WORKABLE = "workable" + ZENDESK = "zendesk" + ZOHO_INVOICE = "zoho-invoice" + ZOHO_MAIL = "zoho-mail" + ZOOM = "zoom" + REDDIT = "reddit" + SALESFORCE = "salesforce" + SERVICEM8 = "servicem8" + TYPEFORM = "typeform" + ALCHEMY = "alchemy" KEAP = "keap" KLIPFOLIO = "klipfolio" + LASTPASS = "lastpass" + ACCELO = "accelo" + ASANA = "asana" + ASHBY = "ashby" + ATTIO = "attio" + GOOGLE_DRIVE = "google-drive" LAUNCH_DARKLY = "launch-darkly" LEXOFFICE = "lexoffice" LINEAR = "linear" LINEARSANDBOX = "linearsandbox" - LINKHUT = "linkhut" - MAILCHIMP = "mailchimp" MAINTAINX = "maintainx" - MICROSOFT_TEAMS = "microsoft-teams" - MICROSOFT_TENANT = "microsoft-tenant" - MIRO = "miro" - MONDAY = "monday" - MOXIE = "moxie" - MURAL = "mural" + BREVO = "brevo" + BREX = "brex" + BREX_STAGING = "brex-staging" + BROWSEAI = "browseai" + FACTORIAL = "factorial" + FIGMA = "figma" + AMAZON = "amazon" + AMCARDS = "amcards" NETSUITE = "netsuite" + NGROK = "ngrok" + NOTION = "notion" ONE_DRIVE = "one-drive" - PAGERDUTY = "pagerduty" PANDADOC = "pandadoc" PIPEDRIVE = "pipedrive" - RAVENSEOTOOLS = "ravenseotools" - REDDIT = "reddit" - RING_CENTRAL = "ring-central" - SAGE = "sage" - SALESFORCE = "salesforce" - SERPAPI = "serpapi" - SERVICEM8 = "servicem8" SHOPIFY = "shopify" + SHORTCUT = "shortcut" + SLACK = "slack" SMARTRECRUITERS = "smartrecruiters" SMUGMUG = "smugmug" - SNOWFLAKE = "snowflake" - SQUARE = "square" - SURVEY_MONKEY = "survey-monkey" - TAPFORM = "tapform" - TODOIST = "todoist" TONEDEN = "toneden" VENLY = "venly" - WABOXAPP = "waboxapp" - YANDEX = "yandex" - YOUTUBE = "youtube" - ZENDESK = "zendesk" ZOHO = "zoho" - ZOHO_BIGIN = "zoho-bigin" - ZOHO_BOOKS = "zoho-books" ZOHO_DESK = "zoho-desk" ZOHO_INVENTORY = "zoho-inventory" - GURU = "guru" + AMPLITUDE = "amplitude" + AUTH0 = "auth0" + BAMBOOHR = "bamboohr" + FRESHBOOKS = "freshbooks" + GORGIAS = "gorgias" + SQUARE = "square" + TODOIST = "todoist" + ZOHO_BIGIN = "zoho-bigin" HEROKU = "heroku" - CALENDALY1 = "calendaly1" - CONVERTKIT = "convertkit" - FRESHSERVICE = "freshservice" - GMAIL1 = "gmail1" - GOOGLE5 = "google5" - GOOGLECALENDAR3 = "googlecalendar3" + INTERCOM = "intercom" KLAVIYO = "klaviyo" - NOTION = "notion" - SENDGRID = "sendgrid" - SLACK = "slack" - SLACK_WITH_ACTIONS = "slack_with_actions" - UBER = "uber" - ACCELO = "accelo" - ADOBE = "adobe" - AERO_WORKFLOW = "aero-workflow" - APIFY = "apify" + MICROSOFT_TEAMS = "microsoft-teams" + MONDAY = "monday" + MOXIE = "moxie" + MURAL = "mural" + ZOHO_BOOKS = "zoho-books" APPDRAG = "appdrag" - ASHBY = "ashby" - ATTIO = "attio" + AXONAUT = "axonaut" + BANNERBEAR = "bannerbear" BASEROW = "baserow" + BATTLENET = "battlenet" BEEMINDER = "beeminder" - BLACKBAUD = "blackbaud" - BOLDSIGN = "boldsign" - BREX = "brex" - BREX_STAGING = "brex-staging" - BROWSERHUB = "browserhub" - BUBBLE = "bubble" - CHATWORK = "chatwork" - CHMEETINGS = "chmeetings" - CLICKUP = "clickup" - CLOSE = "close" + BITWARDEN = "bitwarden" + BOX = "box" + CODEINTERPRETER = "codeinterpreter" DEEL = "deel" - DEMIO = "demio" - DIGICERT = "digicert" DISCORD = "discord" - DROPBOX = "dropbox" DROPBOX_SIGN = "dropbox-sign" ECHTPOST = "echtpost" - EPIC_GAMES = "epic-games" - FACTORIAL = "factorial" - GOOGLE_DRIVE = "google-drive" - GUMROAD = "gumroad" - LASTPASS = "lastpass" - MIXPANEL = "mixpanel" - NGROK = "ngrok" - OKTA = "okta" - PRINTNODE = "printnode" - PROCESS_STREET = "process-street" - SHORTCUT = "shortcut" - SLACKBOT = "slackbot" - SPLITWISE = "splitwise" - TASKADE = "taskade" - TEXTRAZOR = "textrazor" - TIMEKIT = "timekit" - TIMELY = "timely" + EVENTBRITE = "eventbrite" + EXA = "exa" + EXIST = "exist" TINYPNG = "tinypng" TINYURL = "tinyurl" - TRELLO = "trello" - TWITCH = "twitch" - TWITTER = "twitter" - TYPEFORM = "typeform" + ACTIVE_COMPAIGN = "active-compaign" + BOTBABA = "botbaba" + CLOUDFLARE = "cloudflare" + DAILYBOT = "dailybot" + FORMCARRY = "formcarry" + FORMSITE = "formsite" + HELCIM = "helcim" + HUMANLOOP = "humanloop" + INTERZOID = "interzoid" + LEVER = "lever" + LEVER_SANDBOX = "lever-sandbox" + MBOUM = "mboum" + MORE_TREES = "more-trees" + NCSCALE = "ncscale" + ONCEHUB = "oncehub" + PLACEKEY = "placekey" + RAFFLYS = "rafflys" + ROCKET_REACH = "rocket-reach" + SCREENSHOTONE = "screenshotone" + SIMPLESAT = "simplesat" + SPOTIFY = "spotify" + BRAINTREE = "braintree" + BRANDFETCH = "brandfetch" + CALENDLY = "calendly" + CLOSE = "close" + WABOXAPP = "waboxapp" WAKATIME = "wakatime" WAVE_ACCOUNTING = "wave-accounting" - WORKABLE = "workable" + FILEMANAGER = "filemanager" + FITBIT = "fitbit" + FRESHDESK = "freshdesk" + GMAIL = "gmail" + GOOGLE_DOCS = "google-docs" + HARVEST = "harvest" + ALTOVIZ = "altoviz" + COINMARKETCAL = "coinmarketcal" + DATAROBOT = "datarobot" + DOCMOSIS = "docmosis" + FINAGE = "finage" + FLUTTERWAVE = "flutterwave" + FOMO = "fomo" + METATEXTAI = "metatextai" + MOCEAN_API = "mocean-api" + PIGGY = "piggy" + PRODUCTBOARD = "productboard" + QUALAROO = "qualaroo" + TERMINUS = "terminus" + TIMECAMP = "timecamp" + TISANE = "tisane" + VERO = "vero" + WEBFLOW = "webflow" + WORKIOM = "workiom" + YNAB = "ynab" + ZENSERP = "zenserp" WORKSPACE = "workspace" - XERO = "xero" - ZOHO_INVOICE = "zoho-invoice" - ZOHO_MAIL = "zoho-mail" - ZOOM = "zoom" class Action(Enum): @@ -187,6 +214,72 @@ def __init__(self, service, action, no_auth): self.action = action self.no_auth = no_auth + GITHUB_CREATE_ISSUE = ("github", "github_create_issue", False) + GITHUB_LIST_GITHUB_REPOS = ("github", "github_list_github_repos", False) + GITHUB_STAR_REPO = ("github", "github_star_repo", False) + GITHUB_GET_ABOUT_ME = ("github", "github_get_about_me", False) + GITHUB_FETCH_README = ("github", "github_fetch_readme", False) + GITHUB_GET_COMMITS = ("github", "github_get_commits", False) + GITHUB_GET_COMMITS_WITH_CODE = ("github", "github_get_commits_with_code", False) + GITHUB_GET_PATCH_FOR_COMMIT = ("github", "github_get_patch_for_commit", False) + APIFY_LIST_APIFY_ACTORS = ("apify", "apify_list_apify_actors", False) + APIFY_CREATE_APIFY_ACTOR = ("apify", "apify_create_apify_actor", False) + APIFY_GET_ACTOR_ID = ("apify", "apify_get_actor_id", False) + APIFY_SEARCH_STORE = ("apify", "apify_search_store", False) + APIFY_GET_LAST_RUN_DATA = ("apify", "apify_get_last_run_data", False) + APIFY_LIST_APIFY_TASKS = ("apify", "apify_list_apify_tasks", False) + TRELLO_CREATE_TRELLO_LIST = ("trello", "trello_create_trello_list", False) + TRELLO_CREATE_TRELLO_CARD = ("trello", "trello_create_trello_card", False) + TRELLO_GET_TRELLO_BOARD_CARDS = ("trello", "trello_get_trello_board_cards", False) + TRELLO_DELETE_TRELLO_CARD = ("trello", "trello_delete_trello_card", False) + TRELLO_ADD_TRELLO_CARD_COMMENT = ("trello", "trello_add_trello_card_comment", False) + TRELLO_CREATE_TRELLO_LABEL = ("trello", "trello_create_trello_label", False) + TRELLO_UPDATE_TRELLO_BOARD = ("trello", "trello_update_trello_board", False) + TRELLO_GET_ABOUT_ME = ("trello", "trello_get_about_me", False) + TRELLO_SEARCH_TRELLO = ("trello", "trello_search_trello", False) + TRELLO_SEARCH_TRELLO_MEMBER = ("trello", "trello_search_trello_member", False) + TRELLO_UPDATE_TRELLO_CARD = ("trello", "trello_update_trello_card", False) + TRELLO_GET_TRELLO_MEMBER_BOARD = ("trello", "trello_get_trello_member_board", False) + GOOGLECALENDAR_CREATE_GOOGLE_EVENT = ("gcalendar", "googlecalendar_create_google_event", False) + GOOGLECALENDAR_REMOVE_ATTENDEE = ("gcalendar", "googlecalendar_remove_attendee", False) + GOOGLECALENDAR_FIND_EVENT = ("gcalendar", "googlecalendar_find_event", False) + GOOGLECALENDAR_DELETE_GOOGLE_EVENT = ("gcalendar", "googlecalendar_delete_google_event", False) + GOOGLECALENDAR_UPDATE_GOOGLE_EVENT = ("gcalendar", "googlecalendar_update_google_event", False) + GOOGLECALENDAR_FIND_FREE_SLOTS = ("gcalendar", "googlecalendar_find_free_slots", False) + GOOGLECALENDAR_DUPLICATE_GOOGLE_CALENDAR = ("gcalendar", "googlecalendar_duplicate_google_calendar", False) + GOOGLECALENDAR_LIST_GOOGLE_CALENDARS = ("gcalendar", "googlecalendar_list_google_calendars", False) + GOOGLECALENDAR_PATCH_GOOGLE_CALENDAR = ("gcalendar", "googlecalendar_patch_google_calendar", False) + GOOGLECALENDAR_QUICK_ADD_GOOGLE_CALENDAR = ("gcalendar", "googlecalendar_quick_add_google_calendar", False) + GOOGLECALENDAR_GET_CURRENT_DATE_TIME = ("gcalendar", "googlecalendar_get_current_date_time", False) + SLACKBOT_SEND_SLACK_MESSAGE = ("slackbot", "slackbot_send_slack_message", False) + SLACKBOT_LIST_SLACK_CHANNELS = ("slackbot", "slackbot_list_slack_channels", False) + SLACKBOT_LIST_SLACK_MEMBERS = ("slackbot", "slackbot_list_slack_members", False) + SLACKBOT_LIST_SLACK_MESSAGES = ("slackbot", "slackbot_list_slack_messages", False) + CLICKUP_CREATE_TASK = ("clickup", "clickup_create_task", False) + CLICKUP_GET_TASKS = ("clickup", "clickup_get_tasks", False) + CLICKUP_GET_TASK = ("clickup", "clickup_get_task", False) + CLICKUP_CREATE_LIST = ("clickup", "clickup_create_list", False) + CLICKUP_GET_LISTS = ("clickup", "clickup_get_lists", False) + CLICKUP_GET_SPACES = ("clickup", "clickup_get_spaces", False) + CLICKUP_CREATE_SPACE = ("clickup", "clickup_create_space", False) + CLICKUP_CREATE_FOLDER = ("clickup", "clickup_create_folder", False) + CLICKUP_GET_FOLDERS = ("clickup", "clickup_get_folders", False) + SERPAPI_SEARCH = ("serpapi", "serpapi_search", True) + DROPBOX_GET_ABOUT_ME = ("dropbox", "dropbox_get_about_me", False) + SNOWFLAKE_RUN_QUERY = ("snowflake", "snowflake_run_query", False) + SNOWFLAKE_SHOW_TABLES = ("snowflake", "snowflake_show_tables", False) + SNOWFLAKE_DESCRIBE_TABLE = ("snowflake", "snowflake_describe_table", False) + SNOWFLAKE_EXPLORE_COLUMNS = ("snowflake", "snowflake_explore_columns", False) + ZENDESK_CREATE_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_create_zendesk_organization", False) + ZENDESK_DELETE_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_delete_zendesk_organization", False) + ZENDESK_COUNT_ZENDESK_ORGANIZATIONS = ("zendesk", "zendesk_count_zendesk_organizations", False) + ZENDESK_GET_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_get_zendesk_organization", False) + ZENDESK_GET_ALL_ZENDESK_ORGANIZATIONS = ("zendesk", "zendesk_get_all_zendesk_organizations", False) + ZENDESK_UPDATE_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_update_zendesk_organization", False) + ZENDESK_CREATE_ZENDESK_TICKET = ("zendesk", "zendesk_create_zendesk_ticket", False) + ZENDESK_DELETE_ZENDESK_TICKET = ("zendesk", "zendesk_delete_zendesk_ticket", False) + ZENDESK_GET_ABOUT_ME = ("zendesk", "zendesk_get_about_me", False) + TYPEFORM_GET_ABOUT_ME = ("typeform", "typeform_get_about_me", False) ASANA_ALLOCATIONS_GET_RECORD_BY_ID = ("asana", "asana_allocations_get_record_by_id", False) ASANA_ALLOCATIONS_DELETE_ALLOCATION_BY_ID = ("asana", "asana_allocations_delete_allocation_by_id", False) ASANA_ALLOCATIONS_GET_MULTIPLE = ("asana", "asana_allocations_get_multiple", False) @@ -351,63 +444,9 @@ def __init__(self, service, action, no_auth): ASANA_WORK_SPACES_UPDATE_WORK_SPACE_RECORD = ("asana", "asana_work_spaces_update_work_space_record", False) ASANA_WORK_SPACES_ADD_USER_TO_WORK_SPACE = ("asana", "asana_work_spaces_add_user_to_work_space", False) ASANA_WORK_SPACES_REMOVE_USER_FROM_WORK_SPACE = ("asana", "asana_work_spaces_remove_user_from_work_space", False) - CODEINTERPRETER_EXECUTE_CODE = ("codeinterpreter", "codeinterpreter_execute_code", True) - EXA_SEARCH = ("exa", "exa_search", True) - EXA_SIMILARLINK = ("exa", "exa_similarlink", True) - FILEMANAGER_CREATE_SHELL_ACTION = ("filemanager", "filemanager_create_shell_action", True) - FILEMANAGER_CLOSE_SHELL_ACTION = ("filemanager", "filemanager_close_shell_action", True) - FILEMANAGER_RUN_COMMAND_ACTION = ("filemanager", "filemanager_run_command_action", True) - FILEMANAGER_SET_ENV_VAR_ACTION = ("filemanager", "filemanager_set_env_var_action", True) - FILEMANAGER_OPEN_FILE_ACTION = ("filemanager", "filemanager_open_file_action", True) - FILEMANAGER_GOTO_LINE_ACTION = ("filemanager", "filemanager_goto_line_action", True) - FILEMANAGER_SCROLL_ACTION = ("filemanager", "filemanager_scroll_action", True) - FILEMANAGER_CREATE_FILE_ACTION = ("filemanager", "filemanager_create_file_action", True) - FILEMANAGER_EDIT_FILE_ACTION = ("filemanager", "filemanager_edit_file_action", True) - GOOGLECALENDAR_CREATE_GOOGLE_EVENT = ("gcalendar", "googlecalendar_create_google_event", False) - GOOGLECALENDAR_REMOVE_ATTENDEE = ("gcalendar", "googlecalendar_remove_attendee", False) - GOOGLECALENDAR_FIND_EVENT = ("gcalendar", "googlecalendar_find_event", False) - GOOGLECALENDAR_DELETE_GOOGLE_EVENT = ("gcalendar", "googlecalendar_delete_google_event", False) - GOOGLECALENDAR_UPDATE_GOOGLE_EVENT = ("gcalendar", "googlecalendar_update_google_event", False) - GOOGLECALENDAR_FIND_FREE_SLOTS = ("gcalendar", "googlecalendar_find_free_slots", False) - GOOGLECALENDAR_DUPLICATE_GOOGLE_CALENDAR = ("gcalendar", "googlecalendar_duplicate_google_calendar", False) - GOOGLECALENDAR_LIST_GOOGLE_CALENDARS = ("gcalendar", "googlecalendar_list_google_calendars", False) - GOOGLECALENDAR_PATCH_GOOGLE_CALENDAR = ("gcalendar", "googlecalendar_patch_google_calendar", False) - GOOGLECALENDAR_QUICK_ADD_GOOGLE_CALENDAR = ("gcalendar", "googlecalendar_quick_add_google_calendar", False) - GOOGLECALENDAR_GET_CURRENT_DATE_TIME = ("gcalendar", "googlecalendar_get_current_date_time", False) - GITHUB_CREATE_ISSUE = ("github", "github_create_issue", False) - GITHUB_LIST_GITHUB_REPOS = ("github", "github_list_github_repos", False) - GITHUB_STAR_REPO = ("github", "github_star_repo", False) - GITHUB_GET_ABOUT_ME = ("github", "github_get_about_me", False) - GITHUB_FETCH_README = ("github", "github_fetch_readme", False) - GITHUB_GET_COMMITS = ("github", "github_get_commits", False) - GITHUB_GET_COMMITS_WITH_CODE = ("github", "github_get_commits_with_code", False) - GITHUB_GET_PATCH_FOR_COMMIT = ("github", "github_get_patch_for_commit", False) - GMAIL_SEND_EMAIL = ("gmail", "gmail_send_email", False) - GMAIL_CREATE_EMAIL_DRAFT = ("gmail", "gmail_create_email_draft", False) - GMAIL_FIND_EMAIL_ID = ("gmail", "gmail_find_email_id", False) - GMAIL_FETCH_LAST_THREE_MESSAGES = ("gmail", "gmail_fetch_last_three_messages", False) - GMAIL_ADD_LABEL_TO_EMAIL = ("gmail", "gmail_add_label_to_email", False) - GMAIL_LIST_LABELS = ("gmail", "gmail_list_labels", False) - GMAIL_FETCH_MESSAGE_BY_THREAD_ID = ("gmail", "gmail_fetch_message_by_thread_id", False) - GMAIL_REPLY_TO_THREAD = ("gmail", "gmail_reply_to_thread", False) - GMAIL_FETCH_EMAILS_WITH_LABEL = ("gmail", "gmail_fetch_emails_with_label", False) LINEAR_CREATE_LINEAR_ISSUE = ("linear", "linear_create_linear_issue", False) LINEAR_LIST_LINEAR_PROJECTS = ("linear", "linear_list_linear_projects", False) LINEAR_LIST_LINEAR_TEAMS = ("linear", "linear_list_linear_teams", False) - SERPAPI_SEARCH = ("serpapi", "serpapi_search", True) - SNOWFLAKE_RUN_QUERY = ("snowflake", "snowflake_run_query", False) - SNOWFLAKE_SHOW_TABLES = ("snowflake", "snowflake_show_tables", False) - SNOWFLAKE_DESCRIBE_TABLE = ("snowflake", "snowflake_describe_table", False) - SNOWFLAKE_EXPLORE_COLUMNS = ("snowflake", "snowflake_explore_columns", False) - ZENDESK_CREATE_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_create_zendesk_organization", False) - ZENDESK_DELETE_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_delete_zendesk_organization", False) - ZENDESK_COUNT_ZENDESK_ORGANIZATIONS = ("zendesk", "zendesk_count_zendesk_organizations", False) - ZENDESK_GET_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_get_zendesk_organization", False) - ZENDESK_GET_ALL_ZENDESK_ORGANIZATIONS = ("zendesk", "zendesk_get_all_zendesk_organizations", False) - ZENDESK_UPDATE_ZENDESK_ORGANIZATION = ("zendesk", "zendesk_update_zendesk_organization", False) - ZENDESK_CREATE_ZENDESK_TICKET = ("zendesk", "zendesk_create_zendesk_ticket", False) - ZENDESK_DELETE_ZENDESK_TICKET = ("zendesk", "zendesk_delete_zendesk_ticket", False) - ZENDESK_GET_ABOUT_ME = ("zendesk", "zendesk_get_about_me", False) NOTION_GET_ABOUT_ME = ("notion", "notion_get_about_me", False) NOTION_ADD_NOTION_PAGE_CHILDREN = ( "notion", @@ -434,39 +473,27 @@ def __init__(self, service, action, no_auth): SLACK_LIST_SLACK_CHANNELS = ("slack", "slack_list_slack_channels", False) SLACK_LIST_SLACK_MEMBERS = ("slack", "slack_list_slack_members", False) SLACK_LIST_SLACK_MESSAGES = ("slack", "slack_list_slack_messages", False) - APIFY_LIST_APIFY_ACTORS = ("apify", "apify_list_apify_actors", False) - APIFY_CREATE_APIFY_ACTOR = ("apify", "apify_create_apify_actor", False) - APIFY_GET_ACTOR_ID = ("apify", "apify_get_actor_id", False) - APIFY_SEARCH_STORE = ("apify", "apify_search_store", False) - APIFY_GET_LAST_RUN_DATA = ("apify", "apify_get_last_run_data", False) - APIFY_LIST_APIFY_TASKS = ("apify", "apify_list_apify_tasks", False) - CLICKUP_CREATE_TASK = ("clickup", "clickup_create_task", False) - CLICKUP_GET_TASKS = ("clickup", "clickup_get_tasks", False) - CLICKUP_GET_TASK = ("clickup", "clickup_get_task", False) - CLICKUP_CREATE_LIST = ("clickup", "clickup_create_list", False) - CLICKUP_GET_LISTS = ("clickup", "clickup_get_lists", False) - CLICKUP_GET_SPACES = ("clickup", "clickup_get_spaces", False) - CLICKUP_CREATE_SPACE = ("clickup", "clickup_create_space", False) - CLICKUP_CREATE_FOLDER = ("clickup", "clickup_create_folder", False) - CLICKUP_GET_FOLDERS = ("clickup", "clickup_get_folders", False) - DROPBOX_GET_ABOUT_ME = ("dropbox", "dropbox_get_about_me", False) - SLACKBOT_SEND_SLACK_MESSAGE = ("slackbot", "slackbot_send_slack_message", False) - SLACKBOT_LIST_SLACK_CHANNELS = ("slackbot", "slackbot_list_slack_channels", False) - SLACKBOT_LIST_SLACK_MEMBERS = ("slackbot", "slackbot_list_slack_members", False) - SLACKBOT_LIST_SLACK_MESSAGES = ("slackbot", "slackbot_list_slack_messages", False) - TRELLO_CREATE_TRELLO_LIST = ("trello", "trello_create_trello_list", False) - TRELLO_CREATE_TRELLO_CARD = ("trello", "trello_create_trello_card", False) - TRELLO_GET_TRELLO_BOARD_CARDS = ("trello", "trello_get_trello_board_cards", False) - TRELLO_DELETE_TRELLO_CARD = ("trello", "trello_delete_trello_card", False) - TRELLO_ADD_TRELLO_CARD_COMMENT = ("trello", "trello_add_trello_card_comment", False) - TRELLO_CREATE_TRELLO_LABEL = ("trello", "trello_create_trello_label", False) - TRELLO_UPDATE_TRELLO_BOARD = ("trello", "trello_update_trello_board", False) - TRELLO_GET_ABOUT_ME = ("trello", "trello_get_about_me", False) - TRELLO_SEARCH_TRELLO = ("trello", "trello_search_trello", False) - TRELLO_SEARCH_TRELLO_MEMBER = ("trello", "trello_search_trello_member", False) - TRELLO_UPDATE_TRELLO_CARD = ("trello", "trello_update_trello_card", False) - TRELLO_GET_TRELLO_MEMBER_BOARD = ("trello", "trello_get_trello_member_board", False) - TYPEFORM_GET_ABOUT_ME = ("typeform", "typeform_get_about_me", False) + CODEINTERPRETER_EXECUTE_CODE = ("codeinterpreter", "codeinterpreter_execute_code", True) + EXA_SEARCH = ("exa", "exa_search", True) + EXA_SIMILARLINK = ("exa", "exa_similarlink", True) + FILEMANAGER_CREATE_SHELL_ACTION = ("filemanager", "filemanager_create_shell_action", True) + FILEMANAGER_CLOSE_SHELL_ACTION = ("filemanager", "filemanager_close_shell_action", True) + FILEMANAGER_RUN_COMMAND_ACTION = ("filemanager", "filemanager_run_command_action", True) + FILEMANAGER_SET_ENV_VAR_ACTION = ("filemanager", "filemanager_set_env_var_action", True) + FILEMANAGER_OPEN_FILE_ACTION = ("filemanager", "filemanager_open_file_action", True) + FILEMANAGER_GOTO_LINE_ACTION = ("filemanager", "filemanager_goto_line_action", True) + FILEMANAGER_SCROLL_ACTION = ("filemanager", "filemanager_scroll_action", True) + FILEMANAGER_CREATE_FILE_ACTION = ("filemanager", "filemanager_create_file_action", True) + FILEMANAGER_EDIT_FILE_ACTION = ("filemanager", "filemanager_edit_file_action", True) + GMAIL_SEND_EMAIL = ("gmail", "gmail_send_email", False) + GMAIL_CREATE_EMAIL_DRAFT = ("gmail", "gmail_create_email_draft", False) + GMAIL_FIND_EMAIL_ID = ("gmail", "gmail_find_email_id", False) + GMAIL_FETCH_LAST_THREE_MESSAGES = ("gmail", "gmail_fetch_last_three_messages", False) + GMAIL_ADD_LABEL_TO_EMAIL = ("gmail", "gmail_add_label_to_email", False) + GMAIL_LIST_LABELS = ("gmail", "gmail_list_labels", False) + GMAIL_FETCH_MESSAGE_BY_THREAD_ID = ("gmail", "gmail_fetch_message_by_thread_id", False) + GMAIL_REPLY_TO_THREAD = ("gmail", "gmail_reply_to_thread", False) + GMAIL_FETCH_EMAILS_WITH_LABEL = ("gmail", "gmail_fetch_emails_with_label", False) class Trigger(Enum): @@ -476,5 +503,5 @@ def __init__(self, service, trigger): GITHUB_PULL_REQUEST_EVENT = ("github", "github_pull_request_event") GITHUB_COMMIT_EVENT = ("github", "github_commit_event") - SLACK_NEW_MESSAGE = ("slack", "slack_receive_message") SLACKBOT_NEW_MESSAGE = ("slackbot", "slackbot_receive_message") + SLACK_NEW_MESSAGE = ("slack", "slack_receive_message") diff --git a/composio/sdk/sdk.py b/composio/sdk/sdk.py index 02ae437698..ef0830dd15 100644 --- a/composio/sdk/sdk.py +++ b/composio/sdk/sdk.py @@ -3,6 +3,7 @@ from datetime import datetime from enum import Enum from typing import Optional, Union +import warnings from openai import Client from openai.types.beta import thread @@ -16,10 +17,28 @@ from .enums import Action, App, Tag from .storage import get_base_url +from enum import Enum class SchemaFormat(Enum): OPENAI = "openai" DEFAULT = "default" + + +def format_schema(action_schema, format: SchemaFormat = SchemaFormat.OPENAI): + if format == SchemaFormat.OPENAI: + formatted_schema = { + "type": "function", + "function": { + "name": action_schema["name"], + "description": action_schema.get("description", ""), + "parameters": action_schema.get("parameters", {}), + }, + } + else: + formatted_schema = action_schema + # print("Only OPENAI formatting is supported now.") + + return formatted_schema class ConnectionRequest(BaseModel): @@ -126,20 +145,11 @@ def execute_action(self, action_name: Action, params: dict): def get_all_actions(self, format: SchemaFormat = SchemaFormat.OPENAI, tags: list[Union[str, Tag]] = None): app_unique_id = self.appUniqueId - actions = self.sdk_instance.get_list_of_actions(apps=[App(app_unique_id)], tags=tags) - if format == SchemaFormat.OPENAI: - return [ - { - "type": "function", - "function": { - "name": action["name"], - "description": action.get("description", ""), - "parameters": action.get("parameters", {}), - }, - } - for action in actions - ] - return actions + resp = self.sdk_instance.http_client.get( + f"v1/actions?appNames={app_unique_id}" + ) + actions = resp.json() + return [format_schema(action_schema, format = format) for action_schema in actions["items"]] def handle_tools_calls(self, tool_calls: ChatCompletion) -> list[any]: output = [] @@ -312,7 +322,6 @@ def get_list_of_actions( return filtered_actions elif apps is not None and len(apps) > 0: app_unique_ids = [app.value for app in apps] - print(f"app_unique_ids: {app_unique_ids}") resp = self.http_client.get( f"v1/actions?appNames={','.join(app_unique_ids)}" ) @@ -324,7 +333,21 @@ def get_list_of_actions( if item["tags"] and any(tag in item["tags"] for tag in tag_values): filtered_actions.append(item) return filtered_actions - return actions_response["items"] + + warnings.warn( + "Using all the actions of an app is not recommended. " + "Please use tags to filter actions or provide specific actions. " + "We just pass the important actions to the agent, but this is not meant " + "to be used in production.", + UserWarning + ) + actions = actions_response["items"] + important_tag = Tag.IMPORTANT.value[1] + important_actions = [action for action in actions if important_tag in (action.get("tags", []) or [])] + if len(important_actions) > 5: + return important_actions + else: + return actions else: raise ValueError("Either apps or actions must be provided") diff --git a/composio/sdk/utils.py b/composio/sdk/utils.py index 3780a63711..28f34dca0a 100644 --- a/composio/sdk/utils.py +++ b/composio/sdk/utils.py @@ -7,7 +7,7 @@ from .sdk import Composio from .storage import get_base_account_api_key, get_base_url - + def get_enum_key(name): characters_to_replace = [" ", "-", "/", "(", ")", "\\", ":", '"', "'", "."] for char in characters_to_replace: @@ -34,7 +34,7 @@ def generate_enums_given_apps(apps, actions, triggers): enum_content += "class Tag(Enum):\n" for app_key, tags in tag_map.items(): for tag in tags: - tag_name = f'{app_key.upper()}_{tag.upper()}'.replace('.', '_').replace('/', '_').replace('-', '_') + tag_name = get_enum_key(f'{app_key}_{tag}') enum_content += f' {tag_name} = ("{app_key}", "{tag}")\n' enum_content += f' IMPORTANT = ("default", "important")\n' enum_content += "\n" diff --git a/examples/julep_demo.py b/examples/julep_demo.py new file mode 100644 index 0000000000..7252cceac2 --- /dev/null +++ b/examples/julep_demo.py @@ -0,0 +1,82 @@ + +import os +import textwrap +from julep import Client +from dotenv import load_dotenv + +from composio_julep import App, ComposioToolset + + +load_dotenv() +toolset = ComposioToolset() +composio_tools = toolset.get_tools(tools=App.GITHUB) + +api_key = os.environ["JULEP_API_KEY"] +base_url = os.environ["JULEP_API_URL"] +# openai_api_key = os.environ["OPENAI_API_KEY"] + +client = Client(api_key=api_key, base_url=base_url) + + + +name = "Jessica" +about = "Jessica is a forward-thinking tech entrepreneur with a sharp eye for disruptive technologies. She excels in identifying and nurturing innovative tech startups, with a particular interest in sustainability and AI." +default_settings = { + "temperature": 0.7, + "top_p": 1, + "min_p": 0.01, + "presence_penalty": 0, + "frequency_penalty": 0, + "length_penalty": 1.0, + "max_tokens": 150, +} + +agent = client.agents.create( + name=name, + about=about, + default_settings=default_settings, + model="gpt-4", + tools=composio_tools, +) + +about = """ +Sawradip, a software developer, is passionate about impactful tech. +At the tech fair, he seeks investors and collaborators for his project. +""" +user = client.users.create( + name="Sawradip", + about=about, +) + +situation_prompt = """You are Jessica, a key figure in the tech community, always searching for groundbreaking technologies. At a tech fair filled with innovative projects, your goal is to find and support the next big thing. + +Your journey through the fair is highlighted by encounters with various projects, from groundbreaking to niche. You believe in the power of unexpected innovation. + +Recent Tweets +1. 'Amazed by the tech fair's creativity. The future is bright. #TechInnovation' +2. 'Met a developer with a transformative tool for NGOs. This is the +""" + +session = client.sessions.create( + user_id=user.id, agent_id=agent.id, situation=situation_prompt +) + +user_msg = "Hi, I am presenting my project, hosted at github repository SamparkAI/composio_sdk. If you like it, adding a star would be helpful " + +# user_msg = "What do you like about tech?" + +response = client.sessions.chat( + session_id=session.id, + messages=[ + { + "role": "user", + "content": user_msg, + "name": "Sawradip", + } + ], + recall=True, + remember=True, +) + +execution_output = toolset.handle_tool_calls(response) +print(execution_output) \ No newline at end of file diff --git a/examples/openai_demo.py b/examples/openai_demo.py new file mode 100644 index 0000000000..c7d1be5580 --- /dev/null +++ b/examples/openai_demo.py @@ -0,0 +1,30 @@ +import dotenv +from pprint import pprint +from openai import OpenAI +from composio_openai import App, ComposioToolset + + +# Loading the variables from .env file +dotenv.load_dotenv() + +openai_client = OpenAI() + +toolset = ComposioToolset() +actions = toolset.get_tools(tools=App.GITHUB) +# pprint(actions) + +my_task = "Star a repo SamparkAI/composio_sdk on GitHub" + +# Create a chat completion request to decide on the action +response = openai_client.chat.completions.create(model="gpt-4-turbo-preview", + tools=actions, # Passing actions we fetched earlier. + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": my_task} + ] + ) + +pprint(response) + +result = toolset.handle_tool_calls(response) +pprint(result) \ No newline at end of file diff --git a/plugins/autogen/composio_autogen/__init__.py b/plugins/autogen/composio_autogen/__init__.py index cb4ea83a17..9b739279e8 100644 --- a/plugins/autogen/composio_autogen/__init__.py +++ b/plugins/autogen/composio_autogen/__init__.py @@ -1,13 +1,12 @@ from composio import Action, App, Tag -from .autogen_toolspec import ComposioSDK, ComposioToolset, client +from .autogen_toolspec import ComposioToolset, client __all__ = ( "Action", "App", "Tag", - "ComposioSDK", - "ComposioToolset", "client", + "ComposioToolset", ) diff --git a/plugins/autogen/composio_autogen/autogen_toolspec.py b/plugins/autogen/composio_autogen/autogen_toolspec.py index 2f95ee7d5e..fc0e0ce1f0 100644 --- a/plugins/autogen/composio_autogen/autogen_toolspec.py +++ b/plugins/autogen/composio_autogen/autogen_toolspec.py @@ -17,17 +17,17 @@ client = ComposioCore( framework=FrameworkEnum.AUTOGEN, api_key=os.environ.get("COMPOSIO_API_KEY", None) ) -ComposioSDK = client.sdk - class ComposioToolset: def __init__( self, + client: ComposioCore = client, caller=None, executor=None, entity_id: str = "default", connection_ids: Optional[Dict[Union[str, App], str]] = None, ): + self.client = client self.caller = caller self.executor = executor self.entity_id = entity_id @@ -49,12 +49,12 @@ def register_tools( executor or self.executor ), "If executor hasn't been specified during initialization, has to be specified during registration" - if client.is_authenticated() is False: + if self.client.is_authenticated() is False: raise UserNotAuthenticatedException( "User not authenticated. Please authenticate using composio-cli login" ) - action_schemas = client.sdk.get_list_of_actions(apps=tools, tags=tags) + action_schemas = self.client.sdk.get_list_of_actions(apps=tools, tags=tags) for schema in action_schemas: self._register_schema_to_autogen( @@ -79,7 +79,7 @@ def register_actions( executor or self.executor ), "If executor hasn't been specified during initialization, has to be specified during registration" - action_schemas = client.sdk.get_list_of_actions(actions=actions) + action_schemas = self.client.sdk.get_list_of_actions(actions=actions) for schema in action_schemas: self._register_schema_to_autogen( @@ -121,11 +121,8 @@ def _register_schema_to_autogen( action_signature = Signature(parameters=parameters) def placeholder_function(**kwargs): - return client.execute_action( - client.get_action_enum(name, appName), - kwargs, - entity_id=self.entity_id, - connection_id=connection_id, + return self.client.execute_action( + self.client.get_action_enum(name, appName), kwargs, entity_id=self.entity_id, connection_id=connection_id, ) action_func = types.FunctionType( diff --git a/plugins/autogen/setup.py b/plugins/autogen/setup.py index 994dbd2e2b..fed10230a3 100644 --- a/plugins/autogen/setup.py +++ b/plugins/autogen/setup.py @@ -9,7 +9,7 @@ setup( name="composio_autogen", - version="0.2.40", + version="0.2.47", author="Sawradip", author_email="sawradip@composio.dev", description="Use Composio to get an array of tools with your Autogen agent.", @@ -23,7 +23,7 @@ ], python_requires=">=3.9,<4", install_requires=[ - "composio_core===0.2.40", + "composio_core===0.2.47", "pyautogen>=0.2.19", ], include_package_data=True, diff --git a/plugins/crew_ai/setup.py b/plugins/crew_ai/setup.py index 72e08396b0..5125d8077f 100644 --- a/plugins/crew_ai/setup.py +++ b/plugins/crew_ai/setup.py @@ -9,7 +9,7 @@ setup( name="composio_crewai", - version="0.2.40", + version="0.2.47", author="Himanshu", author_email="himanshu@composio.dev", description="Use Composio to get an array of tools with your CrewAI agent.", @@ -23,7 +23,7 @@ ], python_requires=">=3.9,<4", install_requires=[ - "composio_langchain===0.2.40", + "composio_langchain===0.2.47", ], include_package_data=True, ) diff --git a/plugins/julep/README.md b/plugins/julep/README.md new file mode 100644 index 0000000000..8044b1429c --- /dev/null +++ b/plugins/julep/README.md @@ -0,0 +1,133 @@ +## 🚀🔗 Integrating Composio with Julep + +Streamline the integration of Composio within the Julep agentic framework to enhance the interaction capabilities of Julep agents with external applications, significantly extending their operational range and efficiency. + +### Objective + +- **Facilitate the automation of starring a GitHub repository** through the use of conversational commands within the Julep framework, leveraging Composio's OpenAI Function Calls. + +### Installation and Setup + +Ensure you have the necessary packages installed and connect your GitHub account to allow your agents to utilize GitHub functionalities. + +```bash +# Install Composio LangChain package +pip install composio-openai + +# Connect your GitHub account +composio-cli add github + +# View available applications you can connect with +composio-cli show-apps +``` + +### Usage Steps + +#### 1. Initialize Environment and Client + +Set up your development environment by importing essential libraries and configuring the Julep client. +```python + +import os +import textwrap +from julep import Client +from dotenv import load_dotenv + + +load_dotenv() + +api_key = os.environ["JULEP_API_KEY"] +base_url = os.environ["JULEP_API_URL"] +# openai_api_key = os.environ["OPENAI_API_KEY"] + +client = Client(api_key=api_key, base_url=base_url) + + + +name = "Jessica" +about = "Jessica is a forward-thinking tech entrepreneur with a sharp eye for disruptive technologies. She excels in identifying and nurturing innovative tech startups, with a particular interest in sustainability and AI." +default_settings = { + "temperature": 0.7, + "top_p": 1, + "min_p": 0.01, + "presence_penalty": 0, + "frequency_penalty": 0, + "length_penalty": 1.0, + "max_tokens": 150, +} +``` + +### 2. Integrating GitHub Tools with Composio for LangChain Operations + +This section guides you through the process of integrating GitHub tools into your LangChain projects using Composio's services. +```python +from composio_julep import App, ComposioToolset + +toolset = ComposioToolset() +composio_tools = toolset.get_tools(tools=App.GITHUB) + + +agent = client.agents.create( + name=name, + about=about, + default_settings=default_settings, + model="gpt-4", + tools=composio_tools, +) +``` + +### Step 3: Agent Execution + +This step involves configuring and executing the agent to carry out specific tasks, for example, starring a GitHub repository. +```python +about = """ +Sawradip, a software developer, is passionate about impactful tech. +At the tech fair, he seeks investors and collaborators for his project. +""" +user = client.users.create( + name="Sawradip", + about=about, +) + +situation_prompt = """You are Jessica, a key figure in the tech community, always searching for groundbreaking technologies. At a tech fair filled with innovative projects, your goal is to find and support the next big thing. + +Your journey through the fair is highlighted by encounters with various projects, from groundbreaking to niche. You believe in the power of unexpected innovation. + +Recent Tweets +1. 'Amazed by the tech fair's creativity. The future is bright. #TechInnovation' +2. 'Met a developer with a transformative tool for NGOs. This is the +""" + +session = client.sessions.create( + user_id=user.id, agent_id=agent.id, situation=situation_prompt +) + +user_msg = "Hi, I am presenting my project, hosted at github repository SamparkAI/composio_sdk. If you like it, adding a star would be helpful " + +# user_msg = "What do you like about tech?" + +response = client.sessions.chat( + session_id=session.id, + messages=[ + { + "role": "user", + "content": user_msg, + "name": "Sawradip", + } + ], + recall=True, + remember=True, +) + +pprint(response) +``` + +### Step 4: Validate Response + +Execute and validate the response to ensure the task was completed successfully. + +```python +execution_output = toolset.handle_tool_calls(response) +print(execution_output) +``` + diff --git a/plugins/julep/composio_julep/__init__.py b/plugins/julep/composio_julep/__init__.py new file mode 100644 index 0000000000..1fc9167d75 --- /dev/null +++ b/plugins/julep/composio_julep/__init__.py @@ -0,0 +1,10 @@ +from composio import Action, App, Tag + +from .julep_toolspec import ComposioToolset + +__all__ = ( + "Action", + "App", + "Tag", + "ComposioToolset", +) diff --git a/plugins/julep/composio_julep/julep_toolspec.py b/plugins/julep/composio_julep/julep_toolspec.py new file mode 100644 index 0000000000..ba5c5e15d0 --- /dev/null +++ b/plugins/julep/composio_julep/julep_toolspec.py @@ -0,0 +1,47 @@ + +import json +from json.decoder import JSONDecoder +from composio import FrameworkEnum +from composio_openai import OpenaiStyleToolsetBase + +from julep.api.types import ChatResponse + +class ComposioToolset(OpenaiStyleToolsetBase): + def __init__(self, *args, framework=FrameworkEnum.JULEP, **kwargs): + super().__init__(*args, framework=framework, **kwargs) + + + def handle_tool_calls(self, + llm_response: ChatResponse, + entity_id: str = "default") -> list[any]: + outputs = [] + entity = self.client.sdk.get_entity(entity_id) + + for responses in llm_response.response: + for response in responses: + try: + function = json.loads(response.content) + action_name_to_execute = function["name"] + action = self.client.sdk.get_action_enum_without_tool( + action_name=action_name_to_execute + ) + arguments = json.loads(function["arguments"]) + account = entity.get_connection(app_name=action.service) + output = account.execute_action(action, arguments) + + except json.JSONDecodeError: + output = response.content + + outputs.append(output) + + return outputs + + + +if __name__ == '__main__': + from pprint import pprint + from composio import App + + toolset = ComposioToolset() + out = toolset.get_tools(tools=App.GITHUB) + pprint(out) diff --git a/plugins/julep/julep_demo.py b/plugins/julep/julep_demo.py new file mode 100644 index 0000000000..7252cceac2 --- /dev/null +++ b/plugins/julep/julep_demo.py @@ -0,0 +1,82 @@ + +import os +import textwrap +from julep import Client +from dotenv import load_dotenv + +from composio_julep import App, ComposioToolset + + +load_dotenv() +toolset = ComposioToolset() +composio_tools = toolset.get_tools(tools=App.GITHUB) + +api_key = os.environ["JULEP_API_KEY"] +base_url = os.environ["JULEP_API_URL"] +# openai_api_key = os.environ["OPENAI_API_KEY"] + +client = Client(api_key=api_key, base_url=base_url) + + + +name = "Jessica" +about = "Jessica is a forward-thinking tech entrepreneur with a sharp eye for disruptive technologies. She excels in identifying and nurturing innovative tech startups, with a particular interest in sustainability and AI." +default_settings = { + "temperature": 0.7, + "top_p": 1, + "min_p": 0.01, + "presence_penalty": 0, + "frequency_penalty": 0, + "length_penalty": 1.0, + "max_tokens": 150, +} + +agent = client.agents.create( + name=name, + about=about, + default_settings=default_settings, + model="gpt-4", + tools=composio_tools, +) + +about = """ +Sawradip, a software developer, is passionate about impactful tech. +At the tech fair, he seeks investors and collaborators for his project. +""" +user = client.users.create( + name="Sawradip", + about=about, +) + +situation_prompt = """You are Jessica, a key figure in the tech community, always searching for groundbreaking technologies. At a tech fair filled with innovative projects, your goal is to find and support the next big thing. + +Your journey through the fair is highlighted by encounters with various projects, from groundbreaking to niche. You believe in the power of unexpected innovation. + +Recent Tweets +1. 'Amazed by the tech fair's creativity. The future is bright. #TechInnovation' +2. 'Met a developer with a transformative tool for NGOs. This is the +""" + +session = client.sessions.create( + user_id=user.id, agent_id=agent.id, situation=situation_prompt +) + +user_msg = "Hi, I am presenting my project, hosted at github repository SamparkAI/composio_sdk. If you like it, adding a star would be helpful " + +# user_msg = "What do you like about tech?" + +response = client.sessions.chat( + session_id=session.id, + messages=[ + { + "role": "user", + "content": user_msg, + "name": "Sawradip", + } + ], + recall=True, + remember=True, +) + +execution_output = toolset.handle_tool_calls(response) +print(execution_output) \ No newline at end of file diff --git a/plugins/julep/setup.py b/plugins/julep/setup.py new file mode 100644 index 0000000000..6b6317d73f --- /dev/null +++ b/plugins/julep/setup.py @@ -0,0 +1,30 @@ +""" +Setup configuration for Composio Julep plugin. +""" + +from pathlib import Path + +from setuptools import setup + + +setup( + name="composio_julep", + version="0.2.47", + author="Sawradip", + author_email="sawradip@composio.dev", + description="Use Composio to get an array of tools with your Julep wokflow.", + long_description=(Path(__file__).parent / "README.md").read_text(encoding="utf-8"), + long_description_content_type="text/markdown", + url="https://github.com/SamparkAI/composio_sdk", + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + ], + python_requires=">=3.9,<4", + install_requires=[ + "composio_openai===0.2.47", + "julep>=0.3.2" + ], + include_package_data=True, +) diff --git a/plugins/langchain/setup.py b/plugins/langchain/setup.py index c1703228e7..83bb3469a3 100644 --- a/plugins/langchain/setup.py +++ b/plugins/langchain/setup.py @@ -9,7 +9,7 @@ setup( name="composio_langchain", - version="0.2.40", + version="0.2.47", 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.2.40", + "composio_core===0.2.47", ], include_package_data=True, ) diff --git a/plugins/lyzr/composio_lyzr/__init__.py b/plugins/lyzr/composio_lyzr/__init__.py index 78a272f8a9..e9115130b0 100644 --- a/plugins/lyzr/composio_lyzr/__init__.py +++ b/plugins/lyzr/composio_lyzr/__init__.py @@ -1,13 +1,12 @@ from composio import Action, App, Tag -from .lyzr_toolspec import ComposioSDK, ComposioToolset, client +from .lyzr_toolspec import ComposioToolset, client __all__ = ( - "Action", - "App", "Tag", - "ComposioSDK", - "ComposioToolset", + "App", + "Action", "client", + "ComposioToolset", ) diff --git a/plugins/lyzr/composio_lyzr/lyzr_toolspec.py b/plugins/lyzr/composio_lyzr/lyzr_toolspec.py index 68c97ae45d..e38ca59a14 100644 --- a/plugins/lyzr/composio_lyzr/lyzr_toolspec.py +++ b/plugins/lyzr/composio_lyzr/lyzr_toolspec.py @@ -16,16 +16,10 @@ client = ComposioCore( framework=FrameworkEnum.LYZR, api_key=os.environ.get("COMPOSIO_API_KEY", None) ) -ComposioSDK = client.sdk class ComposioToolset: - def __init__( - self, - entity_id: str = "default", - connection_ids: Optional[Dict[Union[str, App], str]] = None, - ): - global client + def __init__(self, client: ComposioCore = client, entity_id: str = "default", connection_ids: Optional[Dict[Union[str, App], str]] = None): self.client = client self.entity_id = entity_id self.connection_ids = connection_ids or {} diff --git a/plugins/lyzr/composio_lyzr/pydantic_utils.py b/plugins/lyzr/composio_lyzr/pydantic_utils.py deleted file mode 100644 index 345a6adbfa..0000000000 --- a/plugins/lyzr/composio_lyzr/pydantic_utils.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import Any, Dict, List, Optional, Type - -from langchain.pydantic_v1 import BaseModel, Field, create_model - - -def json_schema_to_model(json_schema: Dict[str, Any]) -> Type[BaseModel]: - """ - Converts a JSON schema to a Pydantic BaseModel class. - - Args: - json_schema: The JSON schema to convert. - - Returns: - A Pydantic BaseModel class. - """ - - # Extract the model name from the schema title. - model_name = json_schema.get("title") - - # Extract the field definitions from the schema properties. - field_definitions = { - name: json_schema_to_pydantic_field(name, prop, json_schema.get("required", [])) - for name, prop in json_schema.get("properties", {}).items() - } - - # Create the BaseModel class using create_model(). - return create_model(model_name, **field_definitions) - - -def json_schema_to_pydantic_field( - name: str, json_schema: Dict[str, Any], required: List[str] -) -> Any: - """ - Converts a JSON schema property to a Pydantic field definition. - - Args: - name: The field name. - json_schema: The JSON schema property. - - Returns: - A Pydantic field definition. - """ - - # Get the field type. - type_ = json_schema_to_pydantic_type(json_schema) - - # Get the field description. - description = json_schema.get("description") - - # Get the field examples. - examples = json_schema.get("examples", []) - - # Create a Field object with the type, description, and examples. - # The 'required' flag will be set later when creating the model. - return ( - type_, - Field( - description=description, - examples=examples, - default=... if name in required else None, - ), - ) - - -def json_schema_to_pydantic_type(json_schema: Dict[str, Any]) -> Any: - """ - Converts a JSON schema type to a Pydantic type. - - Args: - json_schema: The JSON schema to convert. - - Returns: - A Pydantic type. - """ - - type_ = json_schema.get("type") - - if type_ == "string": - return str - elif type_ == "integer": - return int - elif type_ == "number": - return float - elif type_ == "boolean": - return bool - elif type_ == "array": - items_schema = json_schema.get("items") - if items_schema: - item_type = json_schema_to_pydantic_type(items_schema) - return List[item_type] - else: - return List - elif type_ == "object": - # Handle nested models. - properties = json_schema.get("properties") - if properties: - nested_model = json_schema_to_model(json_schema) - return nested_model - else: - return Dict - elif type_ == "null": - return Optional[Any] # Use Optional[Any] for nullable fields - else: - raise ValueError(f"Unsupported JSON schema type: {type_}") diff --git a/plugins/lyzr/setup.py b/plugins/lyzr/setup.py index 883c803600..6c0ee181f1 100644 --- a/plugins/lyzr/setup.py +++ b/plugins/lyzr/setup.py @@ -9,7 +9,7 @@ setup( name="composio_lyzr", - version="0.2.40", + version="0.2.47", 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.2.40", + "composio_core===0.2.47", "langchain>=0.1.0", ], include_package_data=True, diff --git a/plugins/openai/README.md b/plugins/openai/README.md new file mode 100644 index 0000000000..d3082c27fe --- /dev/null +++ b/plugins/openai/README.md @@ -0,0 +1,73 @@ +## 🚀🔗 Leveraging OpenAI with Composio + +Facilitate the integration of OpenAI with Composio to empower OpenAI models to directly interact with external applications, broadening their capabilities and application scope. + +### Objective + +- **Automate starring a GitHub repository** using conversational instructions via OpenAI Function Calls. + +### Installation and Setup + +Ensure you have the necessary packages installed and connect your GitHub account to allow your agents to utilize GitHub functionalities. + +```bash +# Install Composio LangChain package +pip install composio-openai + +# Connect your GitHub account +composio-cli add github + +# View available applications you can connect with +composio-cli show-apps +``` + +### Usage Steps + +#### 1. Import Base Packages + +Prepare your environment by initializing necessary imports from OpenAI and setting up your client. + +```python +from openai import OpenAI + +# Initialize OpenAI client +openai_client = OpenAI() +``` + +### Step 2: Integrating GitHub Tools with Composio + +This step involves fetching and integrating GitHub tools provided by Composio, enabling enhanced functionality for LangChain operations. +```python +from composio_openai import App, ComposioToolset + +toolset = ComposioToolset() +actions = toolset.get_tools(tools=App.GITHUB) +``` + +### Step 3: Agent Execution + +This step involves configuring and executing the agent to carry out actions, such as starring a GitHub repository. + +```python +my_task = "Star a repo SamparkAI/composio_sdk on GitHub" + +# Create a chat completion request to decide on the action +response = openai_client.chat.completions.create(model="gpt-4-turbo-preview", + tools=actions, # Passing actions we fetched earlier. + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": my_task} + ] + ) + +pprint(response) +``` + +### Step 4: Validate Execution Response + +Execute the following code to validate the response, ensuring that the intended task has been successfully completed. + +```python +result = toolset.handle_tool_calls(response) +pprint(result) +``` diff --git a/plugins/openai/composio_openai/__init__.py b/plugins/openai/composio_openai/__init__.py new file mode 100644 index 0000000000..58b918227e --- /dev/null +++ b/plugins/openai/composio_openai/__init__.py @@ -0,0 +1,10 @@ +from composio import Action, App, Tag + +from .openai_toolspec import ComposioToolset, OpenaiStyleToolsetBase + +__all__ = ( + "Action", + "App", + "Tag", + "ComposioToolset", +) diff --git a/plugins/openai/composio_openai/openai_toolspec.py b/plugins/openai/composio_openai/openai_toolspec.py new file mode 100644 index 0000000000..10c700a952 --- /dev/null +++ b/plugins/openai/composio_openai/openai_toolspec.py @@ -0,0 +1,78 @@ +import hashlib +import logging +import os +import json +import types +from inspect import Signature +from typing import List, Union +from openai.types.chat.chat_completion import ChatCompletion + +from composio.sdk import format_schema +from composio import Action, App, ComposioCore, FrameworkEnum, Tag + +logger = logging.getLogger(__name__) + + +class OpenaiStyleToolsetBase: + def __init__(self, framework = None, entity_id: str = "default"): + self.entity_id = entity_id + self.client = ComposioCore( + framework=framework, api_key=os.environ.get("COMPOSIO_API_KEY", None) + ) + + def get_actions(self, actions: Union[Action, List[Action]]): + if isinstance(actions, Action): + actions = [actions] + + action_schemas = self.client.sdk.get_list_of_actions(actions=actions) + + formatted_schemas = [format_schema(action_schema) for action_schema in action_schemas] + return formatted_schemas + + def get_tools(self, + tools: Union[App, List[App]], + tags: List[Union[str, Tag]] = None): + if isinstance(tools, App): + tools = [tools] + + action_schemas = self.client.sdk.get_list_of_actions(apps=tools, + tags=tags) + formatted_schemas = [format_schema(action_schema) for action_schema in action_schemas] + return formatted_schemas + + def handle_tool_calls(self, + llm_response: ChatCompletion, + entity_id: str = "default") -> list[any]: + output = [] + entity = self.client.sdk.get_entity(entity_id) + try: + if llm_response.choices: + for choice in llm_response.choices: + if choice.message.tool_calls: + for tool_call in choice.message.tool_calls: + action_name_to_execute = tool_call.function.name + action = self.client.sdk.get_action_enum_without_tool( + action_name=action_name_to_execute + ) + arguments = json.loads(tool_call.function.arguments) + account = entity.get_connection(app_name=action.service) + output.append(account.execute_action(action, arguments)) + + except Exception as e: + raise e from e + + return output + + +class ComposioToolset(OpenaiStyleToolsetBase): + def __init__(self, *args, framework=FrameworkEnum.OPENAI, **kwargs): + super().__init__(*args, framework=framework, **kwargs) + + + +if __name__ == '__main__': + from pprint import pprint + + toolset = ComposioToolset() + out = toolset.get_tools(tools=App.GITHUB) + pprint(out) diff --git a/plugins/openai/openai_demo.py b/plugins/openai/openai_demo.py new file mode 100644 index 0000000000..515b5fe7af --- /dev/null +++ b/plugins/openai/openai_demo.py @@ -0,0 +1,25 @@ +from pprint import pprint +from openai import OpenAI +from composio_openai import App, ComposioToolset + +openai_client = OpenAI() + +toolset = ComposioToolset() +actions = toolset.get_tools(tools=App.GITHUB) +# pprint(actions) + +my_task = "Star a repo SamparkAI/composio_sdk on GitHub" + +# Create a chat completion request to decide on the action +response = openai_client.chat.completions.create(model="gpt-4-turbo-preview", + tools=actions, # Passing actions we fetched earlier. + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": my_task} + ] + ) + +pprint(response) + +result = toolset.handle_tool_calls(response) +pprint(result) \ No newline at end of file diff --git a/plugins/openai/setup.py b/plugins/openai/setup.py new file mode 100644 index 0000000000..8c50e72e77 --- /dev/null +++ b/plugins/openai/setup.py @@ -0,0 +1,29 @@ +""" +Setup configuration for Composio OpenAI plugin. +""" + +from pathlib import Path + +from setuptools import setup + + +setup( + name="composio_openai", + version="0.2.47", + author="Sawradip", + author_email="sawradip@composio.dev", + description="Use Composio to get an array of tools with your OpenAI Function Call.", + long_description=(Path(__file__).parent / "README.md").read_text(encoding="utf-8"), + long_description_content_type="text/markdown", + url="https://github.com/SamparkAI/composio_sdk", + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + ], + python_requires=">=3.9,<4", + install_requires=[ + "composio_core===0.2.47", + ], + include_package_data=True, +) diff --git a/scripts/bump.py b/scripts/bump.py index 33bc614d80..68f55e4769 100644 --- a/scripts/bump.py +++ b/scripts/bump.py @@ -67,6 +67,10 @@ def _bump(file: Path, bump_type: BumpType) -> None: f'composio_lyzr==={version}"', f'composio_lyzr==={update}"', ) + content = content.replace( + f'composio_openai==={version}"', + f'composio_openai==={update}"', + ) file.write_text(content, encoding="utf-8") print(f"Bumped {file} to {update}") diff --git a/setup.py b/setup.py index 7976bec977..a2794300db 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="composio_core", - version="0.2.40", + version="0.2.47", author="Utkarsh", author_email="utkarsh@composio.dev", description="Core package to act as a bridge between composio platform and other services.", diff --git a/upload_libs.sh b/upload_libs.sh new file mode 100755 index 0000000000..cd0dce5dbb --- /dev/null +++ b/upload_libs.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -e + +upload_package() { + cd $1 + rm -rf dist/ + python -m build + python -m twine upload --username token --password $PYPI_PASSWORD --repository pypi dist/* + cd .. +} + +upload_package core +upload_package langchain +upload_package crew_ai +upload_package autogen +upload_package lyzr \ No newline at end of file