versionhq 1.1.9.2__py3-none-any.whl → 1.1.9.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- versionhq/__init__.py +3 -3
- versionhq/clients/workflow/model.py +1 -1
- versionhq/tool/__init__.py +7 -4
- versionhq/tool/composio_tool.py +191 -0
- {versionhq-1.1.9.2.dist-info → versionhq-1.1.9.4.dist-info}/METADATA +5 -2
- {versionhq-1.1.9.2.dist-info → versionhq-1.1.9.4.dist-info}/RECORD +9 -9
- {versionhq-1.1.9.2.dist-info → versionhq-1.1.9.4.dist-info}/WHEEL +1 -1
- versionhq/tool/composio.py +0 -161
- {versionhq-1.1.9.2.dist-info → versionhq-1.1.9.4.dist-info}/LICENSE +0 -0
- {versionhq-1.1.9.2.dist-info → versionhq-1.1.9.4.dist-info}/top_level.txt +0 -0
versionhq/__init__.py
CHANGED
@@ -15,10 +15,10 @@ from versionhq.llm.model import LLM
|
|
15
15
|
from versionhq.task.model import Task, TaskOutput
|
16
16
|
from versionhq.team.model import Team, TeamOutput
|
17
17
|
from versionhq.tool.model import Tool
|
18
|
-
from versionhq.tool.
|
18
|
+
from versionhq.tool.composio_tool import ComposioHandler
|
19
19
|
|
20
20
|
|
21
|
-
__version__ = "1.1.9.
|
21
|
+
__version__ = "1.1.9.4"
|
22
22
|
__all__ = [
|
23
23
|
"Agent",
|
24
24
|
"Customer",
|
@@ -34,5 +34,5 @@ __all__ = [
|
|
34
34
|
"Team",
|
35
35
|
"TeamOutput",
|
36
36
|
"Tool",
|
37
|
-
"
|
37
|
+
"ComposioHandler"
|
38
38
|
]
|
@@ -59,7 +59,7 @@ class MessagingComponent(ABC, BaseModel):
|
|
59
59
|
layer_id: int = Field(default=0, description="add id of the layer: 0, 1, 2")
|
60
60
|
message: str = Field(default=None, max_length=1024, description="text message content to be sent")
|
61
61
|
score: InstanceOf[Score] = Field(default=None)
|
62
|
-
condition: str = Field(default=None,
|
62
|
+
condition: str = Field(default=None, description="condition to execute the next component")
|
63
63
|
interval: Optional[str] = Field(default=None, description="ideal interval to set to assess the condition")
|
64
64
|
|
65
65
|
|
versionhq/tool/__init__.py
CHANGED
@@ -40,10 +40,11 @@ composio_app_set = [
|
|
40
40
|
(ComposioAppName.LINKEDIN, ComposioAuthScheme.OAUTH2),
|
41
41
|
]
|
42
42
|
|
43
|
-
class
|
44
|
-
INITIATED = "
|
45
|
-
ACTIVE = "
|
46
|
-
FAILED = "
|
43
|
+
class ComposioStatus(str, Enum):
|
44
|
+
INITIATED = "INITIATED"
|
45
|
+
ACTIVE = "ACTIVE"
|
46
|
+
FAILED = "FAILED"
|
47
|
+
|
47
48
|
|
48
49
|
|
49
50
|
|
@@ -51,3 +52,5 @@ class ComposioAction(str, Enum):
|
|
51
52
|
"""
|
52
53
|
Enum to store composio's action that can be called via `Actions.xxx`
|
53
54
|
"""
|
55
|
+
# HUBSPOT_INITIATE_DATA_IMPORT_PROCESS = "hubspot_initate_date_import_process"
|
56
|
+
HUBSPOT_CREATE_PIPELINE_STAGE = "hubspot_create_pipeline_stage"
|
@@ -0,0 +1,191 @@
|
|
1
|
+
import os
|
2
|
+
import uuid
|
3
|
+
from abc import ABC
|
4
|
+
from dotenv import load_dotenv
|
5
|
+
from typing import Any, Callable, Type, get_args, get_origin, Optional, Tuple, Dict
|
6
|
+
from typing_extensions import Self
|
7
|
+
|
8
|
+
from pydantic import BaseModel, Field, model_validator, field_validator, UUID4, PrivateAttr
|
9
|
+
from pydantic_core import PydanticCustomError
|
10
|
+
|
11
|
+
from composio import ComposioToolSet
|
12
|
+
from composio_langchain import action
|
13
|
+
|
14
|
+
from versionhq.tool import ComposioAppName, ComposioAuthScheme, composio_app_set, ComposioStatus, ComposioAction
|
15
|
+
from versionhq._utils.logger import Logger
|
16
|
+
from versionhq._utils.cache_handler import CacheHandler
|
17
|
+
|
18
|
+
load_dotenv(override=True)
|
19
|
+
|
20
|
+
DEFAULT_REDIRECT_URL = os.environ.get("DEFAULT_REDIRECT_URL", None)
|
21
|
+
DEFAULT_USER_ID = os.environ.get("DEFAULT_USER_ID", None)
|
22
|
+
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", None)
|
23
|
+
|
24
|
+
|
25
|
+
class ComposioHandler(ABC, BaseModel):
|
26
|
+
"""
|
27
|
+
A class to handle connecting account with Composio and executing actions using Composio ecosystem.
|
28
|
+
`connected_account_id` is set up per `app_name` to call the actions on the given app. i.e., salesforce
|
29
|
+
"""
|
30
|
+
|
31
|
+
_logger: Logger = PrivateAttr(default_factory=lambda: Logger(verbose=True))
|
32
|
+
_cache: CacheHandler = PrivateAttr(default_factory=lambda: CacheHandler())
|
33
|
+
|
34
|
+
id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
|
35
|
+
app_name: str = Field(default=ComposioAppName.HUBSPOT, max_length=128, description="app name defined by composio")
|
36
|
+
user_id: str = Field(default=DEFAULT_USER_ID, description="composio entity id")
|
37
|
+
auth_scheme: str = Field(default=ComposioAuthScheme.OAUTH2)
|
38
|
+
redirect_url: str = Field(default=DEFAULT_REDIRECT_URL, description="redirect url after successful oauth2 connection")
|
39
|
+
connected_account_id: str = Field(
|
40
|
+
default=None,
|
41
|
+
description="store the client id generated by composio after auth validation. use the id to connect with a given app and execute composio actions"
|
42
|
+
)
|
43
|
+
tools: Any = Field(default=None, descritpion="retrieved composio tools")
|
44
|
+
|
45
|
+
@field_validator("id", mode="before")
|
46
|
+
@classmethod
|
47
|
+
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
|
48
|
+
if v:
|
49
|
+
raise PydanticCustomError("may_not_set_field", "This field is not to be set by the user.", {})
|
50
|
+
|
51
|
+
|
52
|
+
@model_validator(mode="after")
|
53
|
+
def validate_app_name(self):
|
54
|
+
if self.app_name not in ComposioAppName:
|
55
|
+
raise PydanticCustomError("no_app_name", f"The given app name {self.app_name} is not valid.", {})
|
56
|
+
|
57
|
+
return self
|
58
|
+
|
59
|
+
|
60
|
+
@model_validator(mode="after")
|
61
|
+
def validate_auth_scheme(self):
|
62
|
+
"""
|
63
|
+
Raise error when the client uses auth scheme unavailable for the app.
|
64
|
+
"""
|
65
|
+
app_set = next(filter(lambda tup: self.app_name in tup, composio_app_set), None)
|
66
|
+
if not app_set:
|
67
|
+
raise PydanticCustomError("no_app_set", f"The app set of {self.app_name} is missing.", {})
|
68
|
+
|
69
|
+
else:
|
70
|
+
acceptable_auth_scheme = next(filter(lambda item: self.auth_scheme in item, app_set), None)
|
71
|
+
if acceptable_auth_scheme is None:
|
72
|
+
raise PydanticCustomError("invalid_auth_scheme", f"The app {self.app_name} must have different auth_scheme.", {})
|
73
|
+
|
74
|
+
return self
|
75
|
+
|
76
|
+
|
77
|
+
def _setup_langchain_toolset(self, metadata: Dict[str, Any] = dict()):
|
78
|
+
"""
|
79
|
+
Composio toolset on LangChain for action execution using LLM.
|
80
|
+
"""
|
81
|
+
from composio_langchain import ComposioToolSet
|
82
|
+
return ComposioToolSet(api_key=os.environ.get("COMPOSIO_API_KEY"), metadata={**metadata})
|
83
|
+
|
84
|
+
|
85
|
+
def _connect(
|
86
|
+
self, token: Optional[str] = None, api_key: Optional[str] = None, connected_account_id: str = None
|
87
|
+
) -> Tuple[Self | str | Any]:
|
88
|
+
"""
|
89
|
+
Send connection request to Composio, retrieve `connected_account_id`, and proceed with OAuth process of the given app to activate the connection.
|
90
|
+
"""
|
91
|
+
|
92
|
+
connection_request, connected_account = None, None
|
93
|
+
connected_account_id = connected_account_id or self.connected_account_id
|
94
|
+
if connected_account_id:
|
95
|
+
connected_account = self.toolset.get_connected_account(id=connected_account_id)
|
96
|
+
|
97
|
+
if connected_account and connected_account.status == ComposioStatus.ACTIVE.value:
|
98
|
+
return self, ComposioStatus.ACTIVE.value
|
99
|
+
|
100
|
+
if not self.user_id:
|
101
|
+
raise PydanticCustomError("entity_id_missing", "Need entity_id to connect with the tool", {})
|
102
|
+
|
103
|
+
if self.auth_scheme == ComposioAuthScheme.API_KEY:
|
104
|
+
collected_from_user = {}
|
105
|
+
collected_from_user["api_key"] = api_key
|
106
|
+
connection_request = self.toolset.initiate_connection(
|
107
|
+
connected_account_params = collected_from_user,
|
108
|
+
app=self.app_name,
|
109
|
+
entity_id=self.user_id,
|
110
|
+
auth_scheme=self.auth_scheme,
|
111
|
+
)
|
112
|
+
|
113
|
+
if self.auth_scheme == ComposioAuthScheme.BEARER_TOKEN:
|
114
|
+
collected_from_user = {}
|
115
|
+
collected_from_user["token"] = token
|
116
|
+
connection_request = self.toolset.initiate_connection(
|
117
|
+
connected_account_params = collected_from_user,
|
118
|
+
app=self.app_name,
|
119
|
+
entity_id=self.user_id,
|
120
|
+
auth_scheme=self.auth_scheme,
|
121
|
+
)
|
122
|
+
|
123
|
+
if self.auth_scheme == ComposioAuthScheme.OAUTH2:
|
124
|
+
connection_request = self.toolset.initiate_connection(
|
125
|
+
app=self.app_name,
|
126
|
+
redirect_url = self.redirect_url, # clients will be redirected to this url after successful auth.
|
127
|
+
entity_id=self.user_id,
|
128
|
+
auth_scheme=self.auth_scheme,
|
129
|
+
)
|
130
|
+
|
131
|
+
if connection_request.connectionStatus == ComposioStatus.FAILED.value:
|
132
|
+
self._logger.log(level="error", message="Connection to composio failed.", color="red")
|
133
|
+
raise PydanticCustomError("connection_failed", "Connection to composio has failed", {})
|
134
|
+
|
135
|
+
|
136
|
+
connected_account = self.toolset.get_connected_account(id=connection_request.connectedAccountId)
|
137
|
+
# Note: connected_account.id === connection_request.connectedAccountId === self.connected_account_id
|
138
|
+
|
139
|
+
if connected_account.status == ComposioStatus.ACTIVE.value:
|
140
|
+
setattr(self.toolset, "entity_id", self.user_id)
|
141
|
+
self.connected_account_id = connection_request.connectedAccountId
|
142
|
+
|
143
|
+
elif connected_account.status == ComposioStatus.INITIATED.value:
|
144
|
+
setattr(self.toolset, "entity_id", self.user_id)
|
145
|
+
self.connected_account_id = connection_request.connectedAccountId
|
146
|
+
|
147
|
+
if connection_request.redirectUrl:
|
148
|
+
import webbrowser
|
149
|
+
webbrowser.open(connection_request.redirectUrl)
|
150
|
+
|
151
|
+
else:
|
152
|
+
self._logger.log(level="error", message="The account is invalid.", color="red")
|
153
|
+
raise PydanticCustomError("connection_failed", "Connection to composio has failed", {})
|
154
|
+
|
155
|
+
return self, connected_account.status if connected_account else connection_request.connectionStatus
|
156
|
+
|
157
|
+
|
158
|
+
def execute_composio_action_with_langchain(self, action_name: str | ComposioAction, task_in_natural_language: str) -> Tuple[Self, str]:
|
159
|
+
"""
|
160
|
+
Execute Composio's Action using Langchain's agent ecosystem.
|
161
|
+
"""
|
162
|
+
from langchain import hub
|
163
|
+
from langchain_openai import ChatOpenAI
|
164
|
+
from langchain.agents import create_openai_functions_agent, AgentExecutor
|
165
|
+
from composio_langchain import Action
|
166
|
+
|
167
|
+
action_name = action_name.value if isinstance(action_name, ComposioAction) else action_name
|
168
|
+
action = Action(action_name)
|
169
|
+
metadata = { action: { "OPENAI_API_KEY": OPENAI_API_KEY } }
|
170
|
+
toolset = self._setup_langchain_toolset(metadata=metadata)
|
171
|
+
tools = toolset.get_tools(actions=[action_name,], entity_id=self.user_id)
|
172
|
+
if not tools:
|
173
|
+
self._logger.log(level="error", message=f"Tools related to {action_name} are not found on Langchain", color="red")
|
174
|
+
raise PydanticCustomError("tool_not_found", "Tools not found on Langchain", {})
|
175
|
+
|
176
|
+
self.tools = tools
|
177
|
+
llm = ChatOpenAI()
|
178
|
+
prompt = hub.pull("hwchase17/openai-functions-agent")
|
179
|
+
agent = create_openai_functions_agent(llm, tools, prompt)
|
180
|
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
181
|
+
result = agent_executor.invoke(dict(input=task_in_natural_language))
|
182
|
+
return self, result["output"]
|
183
|
+
|
184
|
+
|
185
|
+
@property
|
186
|
+
def toolset(self) -> ComposioToolSet:
|
187
|
+
return ComposioToolSet(api_key=os.environ.get("COMPOSIO_API_KEY"))
|
188
|
+
|
189
|
+
|
190
|
+
def __name__(self):
|
191
|
+
return self.app_name
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: versionhq
|
3
|
-
Version: 1.1.9.
|
3
|
+
Version: 1.1.9.4
|
4
4
|
Summary: LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows
|
5
5
|
Author-email: Kuriko Iwai <kuriko@versi0n.io>
|
6
6
|
License: MIT License
|
@@ -52,12 +52,15 @@ Requires-Dist: setuptools>=75.6.0
|
|
52
52
|
Requires-Dist: wheel>=0.45.1
|
53
53
|
Requires-Dist: python-dotenv>=1.0.0
|
54
54
|
Requires-Dist: appdirs>=1.4.4
|
55
|
+
Requires-Dist: langchain>=0.3.14
|
56
|
+
Requires-Dist: langchain-openai>=0.2.14
|
57
|
+
Requires-Dist: composio-langchain>=0.6.12
|
55
58
|
|
56
59
|
# Overview
|
57
60
|
|
58
61
|

|
59
62
|
[](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml)
|
60
|
-

|
61
64
|

|
62
65
|

|
63
66
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
versionhq/__init__.py,sha256=
|
1
|
+
versionhq/__init__.py,sha256=7fymmc9s7-Nxwq3vDvY5GA_EYpvpPWR5w9w5Vsv8THs,950
|
2
2
|
versionhq/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
versionhq/_utils/cache_handler.py,sha256=3-lw_5ZMWC8hnPAkSQULJ2V1FvZZ-wg9mQaUJGSOjI8,403
|
4
4
|
versionhq/_utils/i18n.py,sha256=TwA_PnYfDLA6VqlUDPuybdV9lgi3Frh_ASsb_X8jJo8,1483
|
@@ -18,7 +18,7 @@ versionhq/clients/customer/model.py,sha256=Dl2dzo2FUdzqPEgoymeImM18InOmIhytmxAkj
|
|
18
18
|
versionhq/clients/product/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
versionhq/clients/product/model.py,sha256=N8_Oe7W20yYQuJ66owbLD_zNyiSSrYA7i7WI50UuKyQ,2228
|
20
20
|
versionhq/clients/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
-
versionhq/clients/workflow/model.py,sha256=
|
21
|
+
versionhq/clients/workflow/model.py,sha256=SVpYXiq-YQ8Col9iOazKgEqs0VkR4hhSBEOa-myKQVU,5701
|
22
22
|
versionhq/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
versionhq/llm/llm_vars.py,sha256=YZoXqFBW7XpclUZ14_AAz7WOjoyCXnGcI959GSpX2q0,5343
|
24
24
|
versionhq/llm/model.py,sha256=mXzSuf1s6MebGT7_yqgNppde0NIlAF8bjIXAp2MZ9Uw,8247
|
@@ -31,13 +31,13 @@ versionhq/task/model.py,sha256=EbgYHLNq8l1zfRDnF-yEcuSZ0aNvzbRmHYgfVyJq84c,19910
|
|
31
31
|
versionhq/team/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
32
|
versionhq/team/model.py,sha256=E52OUVzUtvR--51SFRJos3JdYKri1t2jbvvzoOvShQc,20181
|
33
33
|
versionhq/team/team_planner.py,sha256=uzX2yed7A7gNSs6qH5jIq2zXMVF5BwQQ4HPATsB9DSQ,3675
|
34
|
-
versionhq/tool/__init__.py,sha256=
|
35
|
-
versionhq/tool/
|
34
|
+
versionhq/tool/__init__.py,sha256=FvBuEXsOQUYnN7RTFxT20kAkiEYkxWKkiVtgpqOzKZQ,1843
|
35
|
+
versionhq/tool/composio_tool.py,sha256=BJqaA1NhV0BT9AdY7OLCGpsAI3VEuCKnOS6D9vuU4zQ,8630
|
36
36
|
versionhq/tool/decorator.py,sha256=W_WjzZy8y43AoiFjHLPUQfNipmpOPe-wQknCWloPwmY,1195
|
37
37
|
versionhq/tool/model.py,sha256=cWfLQVjNkag5cYYqhABBK7-jcpl0UJQWuhDciG3MtPQ,8116
|
38
38
|
versionhq/tool/tool_handler.py,sha256=A3zUkZkx4JEpFHI2uBkHDpzWfADw-bCYUQhgm6rpITM,1569
|
39
|
-
versionhq-1.1.9.
|
40
|
-
versionhq-1.1.9.
|
41
|
-
versionhq-1.1.9.
|
42
|
-
versionhq-1.1.9.
|
43
|
-
versionhq-1.1.9.
|
39
|
+
versionhq-1.1.9.4.dist-info/LICENSE,sha256=7CCXuMrAjPVsUvZrsBq9DsxI2rLDUSYXR_qj4yO_ZII,1077
|
40
|
+
versionhq-1.1.9.4.dist-info/METADATA,sha256=AzBZbuezjj_y0NOYyUrEy488UChQaoUTuSPoOajb_kk,16070
|
41
|
+
versionhq-1.1.9.4.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
42
|
+
versionhq-1.1.9.4.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
|
43
|
+
versionhq-1.1.9.4.dist-info/RECORD,,
|
versionhq/tool/composio.py
DELETED
@@ -1,161 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import uuid
|
3
|
-
from abc import ABC
|
4
|
-
from dotenv import load_dotenv
|
5
|
-
from typing import Any, Callable, Type, get_args, get_origin, Optional, Tuple
|
6
|
-
|
7
|
-
from pydantic import BaseModel, Field, model_validator, field_validator, UUID4, PrivateAttr
|
8
|
-
from pydantic_core import PydanticCustomError
|
9
|
-
|
10
|
-
from composio import ComposioToolSet, Action, App, action
|
11
|
-
|
12
|
-
from versionhq.tool import ComposioAppName, ComposioAuthScheme, composio_app_set, COMPOSIO_STATUS
|
13
|
-
from versionhq._utils.logger import Logger
|
14
|
-
from versionhq._utils.cache_handler import CacheHandler
|
15
|
-
|
16
|
-
load_dotenv(override=True)
|
17
|
-
|
18
|
-
DEFAULT_REDIRECT_URL = os.environ.get("DEFAULT_REDIRECT_URL", None)
|
19
|
-
DEFAULT_USER_ID = os.environ.get("DEFAULT_USER_ID", None)
|
20
|
-
|
21
|
-
|
22
|
-
class Composio(ABC, BaseModel):
|
23
|
-
"""
|
24
|
-
Class to handle composio tools.
|
25
|
-
"""
|
26
|
-
|
27
|
-
_logger: Logger = PrivateAttr(default_factory=lambda: Logger(verbose=True))
|
28
|
-
_cache: CacheHandler
|
29
|
-
|
30
|
-
id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
|
31
|
-
app_name: str = Field(default=ComposioAppName.HUBSPOT)
|
32
|
-
user_id: str = Field(default=DEFAULT_USER_ID)
|
33
|
-
auth_scheme: str = Field(default=ComposioAuthScheme.OAUTH2)
|
34
|
-
redirect_url: str = Field(default=DEFAULT_REDIRECT_URL, description="redirect url after successful oauth2 connection")
|
35
|
-
connect_request_id: str = Field(default=None, description="store the client's composio id to connect with the app")
|
36
|
-
|
37
|
-
@property
|
38
|
-
def toolset(self) -> ComposioToolSet:
|
39
|
-
return ComposioToolSet(api_key=os.environ.get("COMPOSIO_API_KEY"))
|
40
|
-
|
41
|
-
|
42
|
-
def __name__(self):
|
43
|
-
return self.app_name
|
44
|
-
|
45
|
-
|
46
|
-
@field_validator("id", mode="before")
|
47
|
-
@classmethod
|
48
|
-
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
|
49
|
-
if v:
|
50
|
-
raise PydanticCustomError("may_not_set_field", "This field is not to be set by the user.", {})
|
51
|
-
|
52
|
-
|
53
|
-
# @model_validator("user_id", mode="before")
|
54
|
-
# @classmethod
|
55
|
-
# def _deny_no_user_id(cls, v: Optional[str]) -> None:
|
56
|
-
# if v is None:
|
57
|
-
# raise PydanticCustomError("user_id_missing", "Need user_id to connect with the tool", {})
|
58
|
-
|
59
|
-
|
60
|
-
@model_validator(mode="after")
|
61
|
-
def validate_app_name(self):
|
62
|
-
if self.app_name not in ComposioAppName:
|
63
|
-
raise PydanticCustomError("no_app_name", f"The app name {self.app_name} is not valid.", {})
|
64
|
-
|
65
|
-
return self
|
66
|
-
|
67
|
-
|
68
|
-
@model_validator(mode="after")
|
69
|
-
def validate_auth_scheme(self):
|
70
|
-
"""
|
71
|
-
Raise error when the client uses auth scheme unavailable for the app.
|
72
|
-
"""
|
73
|
-
app_set = next(filter(lambda tup: self.app_name in tup, composio_app_set), None)
|
74
|
-
if not app_set:
|
75
|
-
raise PydanticCustomError("no_app_set", f"The app set of {self.app_name} is missing.", {})
|
76
|
-
|
77
|
-
else:
|
78
|
-
acceptable_auth_scheme = next(filter(lambda item: self.auth_scheme in item, app_set), None)
|
79
|
-
if acceptable_auth_scheme is None:
|
80
|
-
raise PydanticCustomError("invalid_auth_scheme", f"The app {self.app_name} must have different auth_scheme.", {})
|
81
|
-
|
82
|
-
return self
|
83
|
-
|
84
|
-
|
85
|
-
# connect with composio to use the tool
|
86
|
-
def connect(self, token: Optional[str] = None, api_key: Optional[str] = None) -> Tuple[str | Any]:
|
87
|
-
"""
|
88
|
-
Connect with Composio, retrieve `connect_request_id`, and validate the connection.
|
89
|
-
"""
|
90
|
-
|
91
|
-
if not self.user_id:
|
92
|
-
raise PydanticCustomError("user_id_missing", "Need user_id to connect with the tool", {})
|
93
|
-
|
94
|
-
|
95
|
-
connection_request, connected_account = None, None
|
96
|
-
|
97
|
-
if self.auth_scheme == ComposioAuthScheme.API_KEY:
|
98
|
-
collected_from_user = {}
|
99
|
-
collected_from_user["api_key"] = api_key
|
100
|
-
connection_request = self.toolset.initiate_connection(
|
101
|
-
connected_account_params = collected_from_user,
|
102
|
-
app=self.app_name,
|
103
|
-
entity_id=self.user_id,
|
104
|
-
auth_scheme=self.auth_scheme,
|
105
|
-
)
|
106
|
-
|
107
|
-
if self.auth_scheme == ComposioAuthScheme.BEARER_TOKEN:
|
108
|
-
collected_from_user = {}
|
109
|
-
collected_from_user["token"] = token
|
110
|
-
connection_request = self.toolset.initiate_connection(
|
111
|
-
connected_account_params = collected_from_user,
|
112
|
-
app=self.app_name,
|
113
|
-
entity_id=self.user_id,
|
114
|
-
auth_scheme=self.auth_scheme,
|
115
|
-
)
|
116
|
-
|
117
|
-
if self.auth_scheme == ComposioAuthScheme.OAUTH2:
|
118
|
-
connection_request = self.toolset.initiate_connection(
|
119
|
-
app=self.app_name,
|
120
|
-
redirect_url = self.redirect_url, # clients will be redirected to this url after successful auth.
|
121
|
-
entity_id=self.user_id,
|
122
|
-
auth_scheme=self.auth_scheme,
|
123
|
-
)
|
124
|
-
|
125
|
-
# connection_request.wait_until_active(self.toolset.client, timeout=60)
|
126
|
-
|
127
|
-
if connection_request.connectionStatus is not COMPOSIO_STATUS.FAILED:
|
128
|
-
self.connect_request_id = connection_request.connectedAccountId
|
129
|
-
connected_account = self.toolset.get_connected_account(id=self.connect_request_id)
|
130
|
-
|
131
|
-
if connected_account.status is not COMPOSIO_STATUS.FAILED:
|
132
|
-
setattr(self.toolset, "entity_id", self.user_id)
|
133
|
-
|
134
|
-
else:
|
135
|
-
self._logger.log(level="error", message="The account is not valid.", color="red")
|
136
|
-
|
137
|
-
else:
|
138
|
-
self._logger.log(level="error", message="Connection to composio failed.", color="red")
|
139
|
-
|
140
|
-
return connected_account, connected_account.status if connected_account else connection_request.connectionStatus
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# @action(toolname=ComposioAppName.HUBSPOT)
|
146
|
-
# def deploy(self, param1: str, param2: str, execute_request: Callable) -> str:
|
147
|
-
# """
|
148
|
-
# Define custom actions
|
149
|
-
# my custom action description which will be passed to llm
|
150
|
-
|
151
|
-
# :param param1: param1 description which will be passed to llm
|
152
|
-
# :param param2: param2 description which will be passed to llm
|
153
|
-
# :return info: return description
|
154
|
-
# """
|
155
|
-
|
156
|
-
# response = execute_request(
|
157
|
-
# "/my_action_endpoint",
|
158
|
-
# "GET",
|
159
|
-
# {} # body can be added here
|
160
|
-
# ) # execute requests by appending credentials to the request
|
161
|
-
# return str(response) # complete auth dict is available for local use if needed
|
File without changes
|
File without changes
|